summaryrefslogtreecommitdiffstats
path: root/ansible_collections/community/windows/tests/integration
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:04:41 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:04:41 +0000
commit975f66f2eebe9dadba04f275774d4ab83f74cf25 (patch)
tree89bd26a93aaae6a25749145b7e4bca4a1e75b2be /ansible_collections/community/windows/tests/integration
parentInitial commit. (diff)
downloadansible-975f66f2eebe9dadba04f275774d4ab83f74cf25.tar.xz
ansible-975f66f2eebe9dadba04f275774d4ab83f74cf25.zip
Adding upstream version 7.7.0+dfsg.upstream/7.7.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ansible_collections/community/windows/tests/integration')
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/psexec/aliases3
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/psexec/tasks/main.yml49
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/psexec/tasks/tests.yml231
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/setup_domain_tests/tasks/main.yml61
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/setup_http_tests/defaults/main.yml4
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/setup_http_tests/handlers/main.yml6
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/setup_http_tests/meta/main.yml2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/setup_http_tests/tasks/main.yml42
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/setup_http_tests/vars/httptester.yml5
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/setup_remote_tmp_dir/handlers/main.yml4
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/setup_remote_tmp_dir/tasks/main.yml11
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/setup_win_device/handlers/main.yml5
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/setup_win_device/library/win_device.ps1546
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/setup_win_device/tasks/main.yml22
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/setup_win_psget/meta/main.yml2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/setup_win_psget/tasks/main.yml129
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_audit_policy_system/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_audit_policy_system/defaults/main.yml3
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_audit_policy_system/tasks/add.yml108
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_audit_policy_system/tasks/main.yml25
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_audit_policy_system/tasks/remove.yml96
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_audit_rule/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_audit_rule/defaults/main.yml7
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_audit_rule/library/test_get_audit_rule.ps193
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_audit_rule/tasks/add.yml172
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_audit_rule/tasks/main.yml33
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_audit_rule/tasks/modify.yml172
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_audit_rule/tasks/remove.yml151
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_auto_logon/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_auto_logon/defaults/main.yml3
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_auto_logon/library/test_autologon_info.ps1215
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_auto_logon/tasks/main.yml42
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_auto_logon/tasks/tests.yml178
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_certificate_info/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_certificate_info/defaults/main.yml3
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_certificate_info/files/root-cert.pem20
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_certificate_info/files/subj-cert.pem19
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_certificate_info/meta/main.yml2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_certificate_info/tasks/main.yml88
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_certificate_info/tasks/tests.yml90
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_computer_description/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_computer_description/defaults/main.yml6
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_computer_description/tasks/main.yml200
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_credential/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_credential/defaults/main.yml19
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_credential/files/cert.pfxbin0 -> 2373 bytes
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_credential/library/test_cred_facts.ps1501
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_credential/meta/main.yml2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_credential/tasks/main.yml64
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_credential/tasks/tests.yml638
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/aliases2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/meta/main.yml2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/tasks/main.yml2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/tasks/pre_test.yml40
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/tasks/tests.yml47
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/templates/partition_creation_script.j211
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/templates/partition_deletion_script.j23
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_dhcp_lease/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_dhcp_lease/defaults/main.yml8
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_dhcp_lease/tasks/main.yml27
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_dhcp_lease/tasks/tests.yml108
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_dhcp_lease/tasks/tests_checkmode.yml52
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_disk_facts/aliases3
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_disk_facts/tasks/main.yml13
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_disk_facts/tasks/tests.yml89
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_dns_record/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_dns_record/defaults/main.yml3
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/clean.yml17
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/main.yml12
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-A.yml294
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-AAAA.yml186
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-CNAME.yml205
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-DHCID.yml234
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-NS.yml277
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-PTR.yml186
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-SRV.yml321
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-TXT.yml234
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-diff.yml63
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests.yml36
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_dns_zone/aliases2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_dns_zone/defaults/main.yml7
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_dns_zone/tasks/activedirectory.yml306
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_dns_zone/tasks/main.yml3
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_dns_zone/tasks/standalone.yml251
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_domain_computer/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_domain_computer/tasks/main.yml478
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_domain_group/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_domain_group/defaults/main.yml3
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_domain_group/tasks/main.yml353
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_domain_object_info/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_domain_object_info/handlers/main.yml5
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_domain_object_info/tasks/main.yml125
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_domain_ou/aliases2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_domain_ou/defaults/main.yml22
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_domain_ou/meta/main.yml3
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_domain_ou/tasks/check_mode_test.yml116
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_domain_ou/tasks/main.yml6
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_domain_ou/tasks/tests.yml190
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_domain_user/aliases2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_domain_user/meta/main.yml3
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_domain_user/tasks/check_mode_test.yml27
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_domain_user/tasks/main.yml18
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_domain_user/tasks/test1.yml76
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_domain_user/tasks/test2.yml171
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_dotnet_ngen/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_dotnet_ngen/tasks/main.yml20
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_eventlog/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_eventlog/tasks/main.yml10
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_eventlog/tasks/tests.yml447
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_eventlog_entry/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_eventlog_entry/defaults/main.yml6
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_eventlog_entry/library/test_win_eventlog_entry.ps133
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_eventlog_entry/tasks/main.yml33
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_eventlog_entry/tasks/tests.yml159
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_feature_info/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_feature_info/defaults/main.yml2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_feature_info/tasks/main.yml58
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_file_compression/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_file_compression/defaults/main.yml5
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_file_compression/meta/main.yml2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_file_compression/tasks/main.yml224
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_firewall/aliases3
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_firewall/tasks/main.yml52
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_firewall/tasks/tests.yml268
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_firewall_rule/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_firewall_rule/tasks/main.yml609
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_format/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_format/meta/main.yml2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_format/tasks/main.yml7
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_format/tasks/pre_test.yml21
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_format/tasks/tests.yml182
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_format/templates/partition_creation_script.j211
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_format/templates/partition_deletion_script.j23
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_hosts/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_hosts/defaults/main.yml13
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_hosts/meta/main.yml2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_hosts/tasks/main.yml17
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_hosts/tasks/tests.yml189
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_hotfix/aliases2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_hotfix/defaults/main.yml13
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_hotfix/tasks/main.yml54
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_hotfix/tasks/tests.yml35
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_hotfix/tasks/tests_2012R2.yml265
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_http_proxy/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_http_proxy/tasks/main.yml14
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_http_proxy/tasks/tests.yml265
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_iis_virtualdirectory/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_iis_virtualdirectory/defaults/main.yml10
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_iis_virtualdirectory/meta/main.yml3
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_iis_virtualdirectory/tasks/main.yml90
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_iis_virtualdirectory/tasks/tests.yml111
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_iis_webapplication/aliases2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_iis_webapplication/defaults/main.yml11
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_iis_webapplication/meta/main.yml3
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_iis_webapplication/tasks/main.yml84
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_iis_webapplication/tasks/tests.yml91
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_iis_webapppool/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_iis_webapppool/defaults/main.yml1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_iis_webapppool/tasks/main.yml43
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_iis_webapppool/tasks/tests.yml424
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/defaults/main.yml30
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/library/test_get_webbindings.ps1106
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/tasks/failures.yml70
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/tasks/http.yml317
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/tasks/https-ge6.2.yml459
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/tasks/https-lt6.2.yml423
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/tasks/main.yml62
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/tasks/setup.yml93
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_inet_proxy/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_inet_proxy/library/win_inet_proxy_info.ps1275
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_inet_proxy/library/win_phonebook_entry.ps1523
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_inet_proxy/tasks/main.yml16
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_inet_proxy/tasks/tests.yml308
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_initialize_disk/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_initialize_disk/defaults/main.yml1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_initialize_disk/tasks/main.yml28
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_initialize_disk/tasks/tests.yml104
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_initialize_disk/templates/vhdx_creation_script.j25
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_initialize_disk/templates/vhdx_deletion_script.j23
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/.gitattributes4
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/01_new_line_at_bof.txt6
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/02_new_line_at_eof.txt7
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/03_new_line_after_1.txt8
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/04_new_line_before_5.txt9
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/05_new_line_at_REF.txt9
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/06_remove_middle_line.txt8
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/07_remove_line_5.txt7
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/08_no_expected_change.txt7
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/09_new_file.txt1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/10_no_eof_new_at_eof.txt3
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/11_multiline_at_eof.txt9
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/12_empty_file_add_at_eof.txt1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/13_new_4_with_backref.txt9
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/14_quoting_code.txt3
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/15_single_quote.txt4
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/16_multiple_quotes.txt5
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/17_new_file_win.txt1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/18_sep_win.txt2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/19_new_file_unix.text1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/20_sep_unix.text2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/21_utf8_no_bom.txt1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/22_utf8_no_bom_line_added.txt2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/23_utf8_bom.txt1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/24_utf8_bom_line_added.txt2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/25_utf16.txt161
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/26_utf16_line_added.txt162
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/27_utf32.txt321
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/28_utf32_line_added.txt322
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/29_no_linebreak.txt1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/30_linebreaks_checksum_bad.txt3
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/31_relative_path.txt6
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/99_README.md36
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/test.txt5
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/test_linebreak.txt0
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/test_quoting.txt0
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/testempty.txt0
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/testnoeof.txt2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/meta/main.yml2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_lineinfile/tasks/main.yml803
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_listen_ports_facts/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_listen_ports_facts/tasks/main.yml45
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_mapped_drive/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_mapped_drive/defaults/main.yml9
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_mapped_drive/tasks/main.yml99
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_mapped_drive/tasks/tests.yml344
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_msg/aliases2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_msg/tasks/main.yml33
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_net_adapter_feature/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_net_adapter_feature/meta/main.yml2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_net_adapter_feature/tasks/main.yml27
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_net_adapter_feature/tasks/tests.yml284
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_netbios/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_netbios/meta/main.yml2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_netbios/tasks/main.yml30
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_netbios/tasks/tests.yml159
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_nssm/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_nssm/defaults/main.yml4
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_nssm/meta/main.yml2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_nssm/tasks/main.yml56
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_nssm/tasks/tests.yml615
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_pagefile/aliases2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_pagefile/tasks/main.yml241
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_partition/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_partition/defaults/main.yml1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_partition/meta/main.yml2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_partition/tasks/main.yml18
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_partition/tasks/tests.yml261
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_partition/templates/vhdx_creation_script.j27
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_partition/templates/vhdx_deletion_script.j23
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_pester/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_pester/defaults/main.yml3
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_pester/files/fail.ps12
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_pester/files/test01.tests.ps15
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_pester/files/test02.tests.ps15
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_pester/files/test03.tests.ps111
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_pester/files/test04.tests.ps118
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_pester/tasks/main.yml60
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_pester/tasks/test.yml134
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_power_plan/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_power_plan/tasks/main.yml128
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_product_facts/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_product_facts/tasks/main.yml11
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psexec/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psexec/meta/main.yml2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psexec/tasks/main.yml102
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psmodule/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/module/license.txt21
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/module/template.nuspec15
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/module/template.psd117
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/module/template.psm110
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/openssl.conf9
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/setup_certs.sh19
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/setup_modules.ps189
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psmodule/handlers/main.yml34
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psmodule/meta/main.yml3
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psmodule/tasks/main.yml513
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psmodule/tasks/setup.yml119
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/defaults/main.yml70
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/files/ansiblevault.0.3.0.nupkgbin0 -> 20797 bytes
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/files/pinvokehelper.0.1.0.nupkgbin0 -> 8632 bytes
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/files/pscsharpinvoker.0.1.0.nupkgbin0 -> 7512 bytes
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/meta/main.yml3
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/tasks/common.yml37
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/tasks/contains_all_fields.yml13
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/tasks/main.yml49
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/tasks/tests.yml85
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psrepository/aliases2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psrepository/defaults/main.yml25
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psrepository/meta/main.yml4
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psrepository/tasks/get_repo_info.yml17
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psrepository/tasks/main.yml18
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psrepository/tasks/tests.yml200
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psrepository/tasks/update_and_force.yml368
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/defaults/main.yml12
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/files/SampleRepositories.xml94
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/meta/main.yml3
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/main.yml95
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/remove_test_profiles.yml42
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/reset.yml22
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/test_by_user.yml32
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/test_exclude_profile.yml58
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/test_exclude_repo.yml49
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/test_include_profile.yml59
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/test_include_repo.yml49
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/test_system_users.yml68
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psrepository_info/aliases3
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psrepository_info/defaults/main.yml10
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psrepository_info/meta/main.yml3
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psrepository_info/tasks/contains_all_fields.yml21
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psrepository_info/tasks/empty.yml19
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psrepository_info/tasks/main.yml51
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psrepository_info/tasks/multiple.yml37
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psrepository_info/tasks/single.yml26
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psscript/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psscript/defaults/main.yml26
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psscript/handlers/main.yml22
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psscript/meta/main.yml3
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psscript/tasks/main.yml13
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psscript/tasks/script_info.yml81
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psscript/tasks/setup_repos.yml58
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psscript/tasks/tests.yml555
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psscript_info/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psscript_info/defaults/main.yml34
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psscript_info/files/install-git.1.0.5.nupkgbin0 -> 4278 bytes
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psscript_info/files/install-wmf3hotfix.1.0.0.nupkgbin0 -> 6294 bytes
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psscript_info/files/test-rpc.1.0.0.nupkgbin0 -> 5891 bytes
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psscript_info/files/upgrade-powershell.1.0.0.nupkgbin0 -> 10305 bytes
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psscript_info/meta/main.yml3
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psscript_info/tasks/common.yml37
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psscript_info/tasks/contains_all_fields.yml13
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psscript_info/tasks/main.yml49
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psscript_info/tasks/tests.yml92
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_pssession_configuration/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_pssession_configuration/defaults/main.yml3
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_pssession_configuration/meta/main.yml2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_pssession_configuration/tasks/main.yml21
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_pssession_configuration/tasks/tests.yml448
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_rabbitmq_plugin/aliases2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_rabbitmq_plugin/tasks/main.yml7
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_rabbitmq_plugin/tasks/tests.yml134
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_rds/aliases5
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_rds/defaults/main.yml9
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_rds/meta/main.yml2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_rds/tasks/main.yml73
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_rds/tasks/win_rds_cap.yml9
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_rds/tasks/win_rds_cap_tests.yml264
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_rds/tasks/win_rds_rap.yml9
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_rds/tasks/win_rds_rap_tests.yml254
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_rds/tasks/win_rds_settings.yml66
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_rds/tasks/win_rds_settings_tests.yml89
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_rds/templates/rds_base_cfg.xml.j258
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_region/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_region/tasks/main.yml252
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_regmerge/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_regmerge/files/settings1.regbin0 -> 374 bytes
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_regmerge/files/settings2.regbin0 -> 760 bytes
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_regmerge/files/settings3.regbin0 -> 1926 bytes
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_regmerge/meta/main.yml2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_regmerge/tasks/main.yml133
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_regmerge/templates/win_line_ending.j24
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_regmerge/vars/main.yml1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_route/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_route/defaults/main.yml3
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_route/tasks/main.yml29
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_route/tasks/tests.yml79
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_say/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_say/tasks/main.yml44
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/defaults/main.yml15
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/tasks/clean.yml16
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/tasks/failures.yml161
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/tasks/main.yml24
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/tasks/principals.yml436
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/tasks/tests.yml440
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/tasks/triggers.yml851
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_scheduled_task_stat/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_scheduled_task_stat/defaults/main.yml5
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_scheduled_task_stat/tasks/main.yml47
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_scheduled_task_stat/tasks/tests.yml175
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_scoop/aliases3
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_scoop/defaults/main.yml6
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_scoop/tasks/main.yml8
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_scoop/tasks/tests.yml159
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_scoop_bucket/aliases3
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_scoop_bucket/defaults/main.yml9
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_scoop_bucket/tasks/main.yml18
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_scoop_bucket/tasks/tests.yml86
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_security_policy/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_security_policy/library/test_win_security_policy.ps155
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_security_policy/tasks/main.yml71
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_security_policy/tasks/tests.yml186
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_shortcut/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_shortcut/tasks/clean.yml37
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_shortcut/tasks/main.yml34
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_shortcut/tasks/tests.yml367
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_snmp/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_snmp/tasks/cleanup.yml16
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_snmp/tasks/cleanup_using_module.yml26
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_snmp/tasks/main.yml8
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_snmp/tasks/output_only.yml24
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_snmp/tasks/snmp_community.yml165
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_snmp/tasks/snmp_managers.yml158
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_snmp/vars/main.yml3
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_timezone/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_timezone/tasks/main.yml19
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_timezone/tasks/tests.yml100
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_toast/aliases2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_toast/tasks/main.yml13
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_toast/tasks/setup.yml27
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_toast/tasks/tests.yml106
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_unzip/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_unzip/defaults/main.yml1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_unzip/files/create_crafty_zip_files.py65
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_unzip/files/create_zip.py28
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_unzip/meta/main.yml2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_unzip/tasks/main.yml171
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_user_profile/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_user_profile/tasks/main.yml42
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_user_profile/tasks/tests.yml374
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_wait_for_process/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_wait_for_process/tasks/main.yml201
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_wakeonlan/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_wakeonlan/tasks/main.yml9
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_xml/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_xml/files/books.xml10
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_xml/files/config.xml5
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_xml/files/log4j.xml49
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_xml/files/plane.zipbin0 -> 792 bytes
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_xml/meta/main.yml2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_xml/tasks/main.yml361
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_zip/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_zip/defaults/main.yml2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_zip/meta/main.yml2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_zip/tasks/main.yml165
438 files changed, 30050 insertions, 0 deletions
diff --git a/ansible_collections/community/windows/tests/integration/targets/psexec/aliases b/ansible_collections/community/windows/tests/integration/targets/psexec/aliases
new file mode 100644
index 000000000..d76b41fdb
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/psexec/aliases
@@ -0,0 +1,3 @@
+windows
+shippable/windows/group5
+
diff --git a/ansible_collections/community/windows/tests/integration/targets/psexec/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/psexec/tasks/main.yml
new file mode 100644
index 000000000..3b0471436
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/psexec/tasks/main.yml
@@ -0,0 +1,49 @@
+---
+- name: check whether the host supports encryption
+ ansible.windows.win_shell: |
+ if ([System.Environment]::OSVersion.Version -lt [Version]"6.2") {
+ "false"
+ } else {
+ "true"
+ }
+ register: encryption_supported_raw
+
+- name: install pypsexec Python library for tests
+ command: '{{ ansible_python_interpreter | default("python") }} -m pip install pypsexec'
+ register: psexec_install
+ changed_when: '"Requirement already satisfied: pypsexec" not in psexec_install.stdout'
+ delegate_to: localhost
+
+- name: define psexec variables
+ set_fact:
+ psexec_hostname: '{{ansible_host}}'
+ psexec_username: '{{ansible_user}}'
+ psexec_password: '{{ansible_password}}'
+ psexec_encrypt: '{{encryption_supported_raw.stdout_lines[0]|bool}}'
+
+- name: create test rule to allow SMB traffic inbound
+ win_firewall_rule:
+ name: File and Printer Sharing (SMB-In) Test
+ direction: in
+ action: allow
+ localport: 445
+ enabled: yes
+ protocol: tcp
+ program: System
+ profiles:
+ - domain
+ - private
+ - public
+ state: present
+
+- name: run tests
+ block:
+ - include_tasks: tests.yml
+
+ always:
+ - name: remove test rule that allows SMB traffic inbound
+ win_firewall_rule:
+ name: File and Printer Sharing (SMB-In) Test
+ direction: in
+ action: allow
+ state: absent
diff --git a/ansible_collections/community/windows/tests/integration/targets/psexec/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/psexec/tasks/tests.yml
new file mode 100644
index 000000000..b542cb43e
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/psexec/tasks/tests.yml
@@ -0,0 +1,231 @@
+---
+- name: fail when process_password is not set with process_username
+ psexec:
+ hostname: '{{psexec_hostname}}'
+ connection_username: '{{psexec_username}}'
+ connection_password: '{{psexec_password}}'
+ encrypt: '{{psexec_encrypt}}'
+ executable: hostname.exe
+ process_username: '{{psexec_username}}'
+ delegate_to: localhost
+ register: fail_no_process_pass
+ failed_when: 'fail_no_process_pass.msg != "parameters are required together when not running as System: process_username, process_password"'
+
+- name: get current host
+ ansible.windows.win_command: hostname.exe
+ register: actual_hostname
+
+- name: run basic psexec command
+ psexec:
+ hostname: '{{psexec_hostname}}'
+ connection_username: '{{psexec_username}}'
+ connection_password: '{{psexec_password}}'
+ encrypt: '{{psexec_encrypt}}'
+ executable: hostname.exe
+ delegate_to: localhost
+ register: psexec_hostname_actual
+
+- name: assert basic psexec command matches expected output
+ assert:
+ that:
+ - psexec_hostname_actual is changed
+ - psexec_hostname_actual.rc == 0
+ - psexec_hostname_actual.stderr == ''
+ - psexec_hostname_actual.stdout == actual_hostname.stdout
+
+- name: get output for executable with arguments
+ ansible.windows.win_command: hostname.exe /?
+ register: actual_hostname_help
+ failed_when: actual_hostname_help.rc != 1
+
+- name: run psexec command with arguments
+ psexec:
+ hostname: '{{psexec_hostname}}'
+ connection_username: '{{psexec_username}}'
+ connection_password: '{{psexec_password}}'
+ encrypt: '{{psexec_encrypt}}'
+ executable: hostname.exe
+ arguments: /?
+ delegate_to: localhost
+ register: psexec_hostname_help
+ failed_when: psexec_hostname_help.rc != 1
+
+- name: assert basic pesexec command with arguments matches expected output
+ assert:
+ that:
+ - psexec_hostname_help is changed
+ - psexec_hostname_help.rc == 1
+ - psexec_hostname_help.stderr == actual_hostname_help.stderr
+ - psexec_hostname_help.stdout == actual_hostname_help.stdout
+
+- name: run psexec command and send data through stdin
+ psexec:
+ hostname: '{{psexec_hostname}}'
+ connection_username: '{{psexec_username}}'
+ connection_password: '{{psexec_password}}'
+ encrypt: '{{psexec_encrypt}}'
+ executable: powershell.exe
+ arguments: '-'
+ stdin: |
+ Write-Host hello world
+ Write-Host this is another message
+ exit 0
+ delegate_to: localhost
+ register: psexec_stdin
+
+- name: assert psexec ommand and send data through stdin
+ assert:
+ that:
+ - psexec_stdin is changed
+ - psexec_stdin.rc == 0
+ - psexec_stdin.stderr == ''
+ - psexec_stdin.stdout == 'hello world\nthis is another message\n'
+
+- name: run psexec command with specific process username
+ psexec:
+ hostname: '{{psexec_hostname}}'
+ connection_username: '{{psexec_username}}'
+ connection_password: '{{psexec_password}}'
+ encrypt: '{{psexec_encrypt}}'
+ load_profile: no # on Azure, the profile does not exist yet so we don't load it for this task
+ executable: powershell.exe
+ arguments: '-'
+ stdin: |
+ ((Get-CimInstance Win32_Process -filter "processid = $pid") | Get-CimAssociatedInstance -Association Win32_SessionProcess).LogonType
+ exit 0
+ process_username: '{{psexec_username}}'
+ process_password: '{{psexec_password}}'
+ delegate_to: localhost
+ register: psexec_process_username
+
+- name: assert psexec command with specific process username
+ assert:
+ that:
+ - psexec_process_username is changed
+ - psexec_process_username.rc == 0
+ - psexec_process_username.stderr == ''
+ - psexec_process_username.stdout_lines[0] != '3' # 3 is Network Logon Type, we assert we are not a network logon with process credentials
+
+- name: run psexec command with both stderr and stdout
+ psexec:
+ hostname: '{{psexec_hostname}}'
+ connection_username: '{{psexec_username}}'
+ connection_password: '{{psexec_password}}'
+ encrypt: '{{psexec_encrypt}}'
+ executable: cmd.exe
+ arguments: /c echo first && echo second 1>&2 && echo third
+ delegate_to: localhost
+ register: psexec_process_stderr
+
+- name: assert psexec command with both stderr and stdout
+ assert:
+ that:
+ - psexec_process_stderr is changed
+ - psexec_process_stderr.rc == 0
+ - psexec_process_stderr.stderr == 'second \r\n'
+ - psexec_process_stderr.stdout == 'first \r\nthird\r\n'
+
+- name: run process asynchronously
+ psexec:
+ hostname: '{{psexec_hostname}}'
+ connection_username: '{{psexec_username}}'
+ connection_password: '{{psexec_password}}'
+ encrypt: '{{psexec_encrypt}}'
+ executable: powershell.exe
+ arguments: Start-Sleep -Seconds 30
+ asynchronous: yes
+ delegate_to: localhost
+ register: psexec_process_async
+
+- name: check if process is still running
+ ansible.windows.win_shell: (Get-Process -ID {{psexec_process_async.pid}}).ProcessName
+ register: psexec_process_async_actual
+
+- name: assert run process asynchronously
+ assert:
+ that:
+ - psexec_process_async is changed
+ - psexec_process_async.rc is not defined
+ - psexec_process_async.pid is defined
+ - psexec_process_async.stdout is not defined
+ - psexec_process_async.stderr is not defined
+ - psexec_process_async_actual.stdout_lines[0] == 'powershell'
+
+- name: run process interactively
+ psexec:
+ hostname: '{{psexec_hostname}}'
+ connection_username: '{{psexec_username}}'
+ connection_password: '{{psexec_password}}'
+ encrypt: '{{psexec_encrypt}}'
+ executable: powershell.exe
+ arguments: Write-Host hi
+ interactive: yes
+ delegate_to: localhost
+ register: psexec_process_interactive
+
+- name: assert run process interactively
+ assert:
+ that:
+ - psexec_process_interactive is changed
+ - psexec_process_interactive.rc == 0
+ - psexec_process_interactive.stdout is not defined
+ - psexec_process_interactive.stderr is not defined
+
+- name: run process with timeout
+ psexec:
+ hostname: '{{psexec_hostname}}'
+ connection_username: '{{psexec_username}}'
+ connection_password: '{{psexec_password}}'
+ encrypt: '{{psexec_encrypt}}'
+ executable: powershell.exe
+ arguments: Start-Sleep -Seconds 30
+ process_timeout: 5
+ delegate_to: localhost
+ register: psexec_process_timeout
+ failed_when: psexec_process_timeout.rc == 0
+
+- name: assert psexec process with timeout
+ assert:
+ that:
+ - psexec_process_timeout.rc != 0
+ - psexec_process_timeout.stdout == ''
+ - psexec_process_timeout.stderr == ''
+
+- name: run process as system
+ psexec:
+ hostname: '{{psexec_hostname}}'
+ connection_username: '{{psexec_username}}'
+ connection_password: '{{psexec_password}}'
+ encrypt: '{{psexec_encrypt}}'
+ executable: whoami.exe
+ process_username: System
+ delegate_to: localhost
+ register: psexec_process_system
+
+- name: assert run process as system
+ assert:
+ that:
+ - psexec_process_system is changed
+ - psexec_process_system.rc == 0
+ - psexec_process_system.stderr == ''
+ - psexec_process_system.stdout == 'nt authority\system\r\n'
+
+- name: run process with different chdir
+ psexec:
+ hostname: '{{psexec_hostname}}'
+ connection_username: '{{psexec_username}}'
+ connection_password: '{{psexec_password}}'
+ encrypt: '{{psexec_encrypt}}'
+ executable: powershell.exe
+ arguments: (pwd).Path
+ working_directory: C:\Windows
+ delegate_to: localhost
+ register: psexec_process_working_dir
+
+- name: assert run process with different chdir
+ assert:
+ that:
+ - psexec_process_working_dir is changed
+ - psexec_process_working_dir.rc == 0
+ - psexec_process_working_dir.stderr == ''
+ - psexec_process_working_dir.stdout == 'C:\Windows\r\n'
diff --git a/ansible_collections/community/windows/tests/integration/targets/setup_domain_tests/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/setup_domain_tests/tasks/main.yml
new file mode 100644
index 000000000..b46d69078
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/setup_domain_tests/tasks/main.yml
@@ -0,0 +1,61 @@
+---
+- name: Change the hostname to ansible-tester
+ ansible.windows.win_hostname:
+ name: ansible-tester
+ register: rename_host
+
+- name: Reboot after changing hostname
+ ansible.windows.win_reboot:
+ when: rename_host.reboot_required
+
+- name: Ensure the ActiveDirectory module is installed
+ ansible.windows.win_feature:
+ name:
+ - RSAT-AD-PowerShell
+ 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 after domain promotion
+ ansible.windows.win_reboot:
+ when: ensure_domain.reboot_required
+
+# While usually win_reboot waits until it is fully done before continuing I've seen Server 2019 in CI still waiting
+# for things to initialise. By tested if ADWS is available with a simple check we can ensure the host is at least
+# ready to test AD. Typically I've found it takes about 60 retries so doubling it should cover even an absolute worst
+# case.
+- name: Post reboot test for ADWS to come online
+ ansible.windows.win_powershell:
+ parameters:
+ Delay: 5
+ Retries: 120
+ script: |
+ [CmdletBinding()]
+ param (
+ [int]$Delay,
+ [int]$Retries
+ )
+ $Ansible.Changed = $false
+ $attempts = 0
+ $err = $null
+ while ($true) {
+ $attempts++
+ try {
+ Get-ADRootDSE -ErrorAction Stop
+ break
+ }
+ catch {
+ if ($attempts -eq $Retries) {
+ throw
+ }
+ Start-Sleep -Seconds $Delay
+ }
+ }
+ $attempts
+ become: yes
+ become_method: runas
+ become_user: SYSTEM
diff --git a/ansible_collections/community/windows/tests/integration/targets/setup_http_tests/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/setup_http_tests/defaults/main.yml
new file mode 100644
index 000000000..a1e5b8d10
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/setup_http_tests/defaults/main.yml
@@ -0,0 +1,4 @@
+badssl_host: wrong.host.badssl.com
+httpbin_host: httpbin.org
+sni_host: ci-files.testing.ansible.com
+badssl_host_substring: wrong.host.badssl.com
diff --git a/ansible_collections/community/windows/tests/integration/targets/setup_http_tests/handlers/main.yml b/ansible_collections/community/windows/tests/integration/targets/setup_http_tests/handlers/main.yml
new file mode 100644
index 000000000..a14627931
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/setup_http_tests/handlers/main.yml
@@ -0,0 +1,6 @@
+- name: remove CA trust store cert
+ ansible.windows.win_certificate_store:
+ thumbprint: '{{ httptester_ca_cert_info.thumbprints[0] }}'
+ state: absent
+ store_location: LocalMachine
+ store_name: Root
diff --git a/ansible_collections/community/windows/tests/integration/targets/setup_http_tests/meta/main.yml b/ansible_collections/community/windows/tests/integration/targets/setup_http_tests/meta/main.yml
new file mode 100644
index 000000000..1810d4bec
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/setup_http_tests/meta/main.yml
@@ -0,0 +1,2 @@
+dependencies:
+ - setup_remote_tmp_dir
diff --git a/ansible_collections/community/windows/tests/integration/targets/setup_http_tests/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/setup_http_tests/tasks/main.yml
new file mode 100644
index 000000000..d4f1d789b
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/setup_http_tests/tasks/main.yml
@@ -0,0 +1,42 @@
+# The docker --link functionality gives us an ENV var we can key off of to see if we have access to
+# the httptester container
+- set_fact:
+ has_httptester: "{{ lookup('env', 'HTTPTESTER') != '' }}"
+
+- name: If we are running with access to a httptester container, grab it's cacert and install it
+ when: has_httptester | bool
+ block:
+ - name: Override hostname defaults with httptester linked names
+ include_vars: httptester.yml
+
+ - name: make sure the port forwarder is active
+ ansible.windows.win_wait_for:
+ host: ansible.http.tests
+ port: 80
+ state: started
+ timeout: 300
+
+ - name: get client cert/key
+ ansible.windows.win_get_url:
+ url: http://ansible.http.tests/{{ item }}
+ dest: '{{ remote_tmp_dir }}\{{ item }}'
+ register: win_download
+ retries: 5 # Just have a retry in case the host is running a bit slower today.
+ until: win_download is successful
+ with_items:
+ - client.pem
+ - client.key
+
+ - name: retrieve test cacert
+ ansible.windows.win_get_url:
+ url: http://ansible.http.tests/cacert.pem
+ dest: '{{ remote_tmp_dir }}\cacert.pem'
+
+ - name: update ca trust
+ ansible.windows.win_certificate_store:
+ path: '{{ remote_tmp_dir }}\cacert.pem'
+ state: present
+ store_location: LocalMachine
+ store_name: Root
+ register: httptester_ca_cert_info
+ notify: remove CA trust store cert
diff --git a/ansible_collections/community/windows/tests/integration/targets/setup_http_tests/vars/httptester.yml b/ansible_collections/community/windows/tests/integration/targets/setup_http_tests/vars/httptester.yml
new file mode 100644
index 000000000..0e23ae936
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/setup_http_tests/vars/httptester.yml
@@ -0,0 +1,5 @@
+# these are fake hostnames provided by docker link for the httptester container
+badssl_host: fail.ansible.http.tests
+httpbin_host: ansible.http.tests
+sni_host: sni1.ansible.http.tests
+badssl_host_substring: HTTP Client Testing Service
diff --git a/ansible_collections/community/windows/tests/integration/targets/setup_remote_tmp_dir/handlers/main.yml b/ansible_collections/community/windows/tests/integration/targets/setup_remote_tmp_dir/handlers/main.yml
new file mode 100644
index 000000000..f0f0ee5ee
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/setup_remote_tmp_dir/handlers/main.yml
@@ -0,0 +1,4 @@
+- name: delete temporary directory
+ ansible.windows.win_file:
+ path: '{{ remote_tmp_dir }}'
+ state: absent
diff --git a/ansible_collections/community/windows/tests/integration/targets/setup_remote_tmp_dir/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/setup_remote_tmp_dir/tasks/main.yml
new file mode 100644
index 000000000..4b6e1395b
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/setup_remote_tmp_dir/tasks/main.yml
@@ -0,0 +1,11 @@
+- name: create temporary directory
+ ansible.windows.win_tempfile:
+ state: directory
+ suffix: .test
+ register: remote_tmp_dir
+ notify:
+ - delete temporary directory
+
+- name: record temporary directory
+ set_fact:
+ remote_tmp_dir: "{{ remote_tmp_dir.path }}"
diff --git a/ansible_collections/community/windows/tests/integration/targets/setup_win_device/handlers/main.yml b/ansible_collections/community/windows/tests/integration/targets/setup_win_device/handlers/main.yml
new file mode 100644
index 000000000..5c01331ad
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/setup_win_device/handlers/main.yml
@@ -0,0 +1,5 @@
+---
+- name: remove dummy network adapter device
+ win_device:
+ name: '{{ network_device_name_raw.name }}'
+ state: absent
diff --git a/ansible_collections/community/windows/tests/integration/targets/setup_win_device/library/win_device.ps1 b/ansible_collections/community/windows/tests/integration/targets/setup_win_device/library/win_device.ps1
new file mode 100644
index 000000000..77fac9086
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/setup_win_device/library/win_device.ps1
@@ -0,0 +1,546 @@
+#!powershell
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#Requires -Module Ansible.ModuleUtils.AddType
+
+$spec = @{
+ options = @{
+ hardware_id = @{ type = "str" }
+ name = @{ type = "str" }
+ path = @{ type = "path" }
+ state = @{ type = "str"; choices = @("absent", "present"); default = "present" }
+ }
+ required_if = @(
+ @("state", "present", @("path", "hardware_id"), $true),
+ @("state", "absent", @(, "name"))
+ )
+ supports_check_mode = $true
+}
+
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
+
+$hardware_id = $module.Params.hardware_id
+$name = $module.Params.name
+$path = $module.Params.path
+$state = $module.Params.state
+
+$module.Result.reboot_required = $false
+
+Add-CSharpType -References @'
+using Microsoft.Win32.SafeHandles;
+using System;
+using System.ComponentModel;
+using System.Runtime.ConstrainedExecution;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace Ansible.Device
+{
+ public class NativeHelpers
+ {
+ [StructLayout(LayoutKind.Sequential)]
+ public class SP_DEVINFO_DATA
+ {
+ public UInt32 cbSize;
+ public Guid ClassGuid;
+ public UInt32 DevInst;
+ public IntPtr Reserved;
+
+ public SP_DEVINFO_DATA()
+ {
+ this.cbSize = (UInt32)Marshal.SizeOf(this);
+ this.ClassGuid = Guid.Empty;
+ }
+ }
+
+ [Flags]
+ public enum DeviceInfoCreationFlags : uint
+ {
+ DICD_GENERATE_ID = 0x00000001,
+ DICD_INHERIT_CLASSDRVS = 0x00000002,
+ }
+
+ public enum DeviceProperty : uint
+ {
+ SPDRP_DEVICEDESC = 0x0000000,
+ SPDRP_HARDWAREID = 0x0000001,
+ SPDRP_COMPATIBLEIDS = 0x0000002,
+ SPDRP_UNUSED0 = 0x0000003,
+ SPDRP_SERVICE = 0x0000004,
+ SPDRP_UNUSED1 = 0x0000005,
+ SPDRP_UNUSED2 = 0x0000006,
+ SPDRP_CLASS = 0x0000007, // Read only - tied to ClassGUID
+ SPDRP_CLASSGUID = 0x0000008,
+ SPDRP_DRIVER = 0x0000009,
+ SPDRP_CONFIGFLAGS = 0x000000a,
+ SPDRP_MFG = 0x000000b,
+ SPDRP_FRIENDLYNAME = 0x000000c,
+ SPDRP_LOCATION_INFORMATION = 0x000000d,
+ SPDRP_PHYSICAL_DEVICE_OBJECT_NAME = 0x000000e, // Read only
+ SPDRP_CAPABILITIES = 0x000000f, // Read only
+ SPDRP_UI_NUMBER = 0x0000010, // Read only
+ SPDRP_UPPERFILTERS = 0x0000011,
+ SPDRP_LOWERFILTERS = 0x0000012,
+ SPDRP_BUSTYPEGUID = 0x0000013, // Read only
+ SPDRP_LEGACYBUSTYPE = 0x0000014, // Read only
+ SPDRP_BUSNUMBER = 0x0000015, // Read only
+ SPDRP_ENUMERATOR_NAME = 0x0000016, // Read only
+ SPDRP_SECURITY = 0x0000017,
+ SPDRP_SECURITY_SDS = 0x0000018,
+ SPDRP_DEVTYPE = 0x0000019,
+ SPDRP_EXCLUSIVE = 0x000001a,
+ SPDRP_CHARACTERISTICS = 0x000001b,
+ SPDRP_ADDRESS = 0x000001c, // Read only
+ SPDRP_UI_NUMBER_DESC_FORMAT = 0x000001d,
+ SPDRP_DEVICE_POWER_DATA = 0x000001e, // Read only
+ SPDRP_REMOVAL_POLICY = 0x000001f, // Read only
+ SPDRP_REMOVAL_POLICY_HW_DEFAULT = 0x0000020, // Read only
+ SPDRP_REMOVAL_POLICY_OVERRIDE = 0x0000021,
+ SPDRP_INSTALL_STATE = 0x0000022, // Read only
+ SPDRP_LOCATION_PATHS = 0x0000023, // Read only
+ SPDRP_BASE_CONTAINERID = 0x0000024, // Read only
+ }
+
+ // https://docs.microsoft.com/en-us/previous-versions/ff549793%28v%3dvs.85%29
+ public enum DifCodes : uint
+ {
+ DIF_SELECTDIVE = 0x00000001,
+ DIF_INSTALLDEVICE = 0x00000002,
+ DIF_ASSIGNRESOURCES = 0x00000003,
+ DIF_PROPERTIES = 0x00000004,
+ DIF_REMOVE = 0x00000005,
+ DIF_FIRSTTIMESETUP = 0x00000006,
+ DIF_FOUNDDEVICE = 0x00000007,
+ DIF_SELECTCLASSDRIVERS = 0x00000008,
+ DIF_VALIDATECLASSDRIVERS = 0x00000009,
+ DIF_INSTALLCLASSDRIVERS = 0x0000000a,
+ DIF_CALCDISKSPACE = 0x0000000b,
+ DIF_DESTROYPRIVATEDATA = 0x0000000c,
+ DIF_VALIDATEDRIVER = 0x0000000d,
+ DIF_DETECT = 0x0000000f,
+ DIF_INSTALLWIZARD = 0x00000010,
+ DIF_DESTROYWIZARDDATA = 0x00000011,
+ DIF_PROPERTYCHANGE = 0x00000012,
+ DIF_ENABLECLASS = 0x00000013,
+ DIF_DETECTVERIFY = 0x00000014,
+ DIF_INSTALLDEVICEFILES = 0x00000015,
+ DIF_UNREMOVE = 0x00000016,
+ DIF_SELECTBESTCOMPATDRV = 0x00000017,
+ DIF_ALLOW_INSTALL = 0x00000018,
+ DIF_REGISTERDEVICE = 0x00000019,
+ DIF_NEWDEVICEWIZARD_PRESELECT = 0x0000001a,
+ DIF_NEWDEVICEWIZARD_SELECT = 0x0000001b,
+ DIF_NEWDEVICEWIZARD_PREANALYZE = 0x0000001c,
+ DIF_NEWDEVICEWIZARD_POSTANALYZE = 0x0000001d,
+ DIF_NEWDEVICEWIZARD_FINISHINSTALL = 0x0000001e,
+ DIF_UNUSED1 = 0x0000001e,
+ DIF_INSTALLINTERFACES = 0x00000020,
+ DIF_DETECTCANCEL = 0x00000021,
+ DIF_REGISTER_COINSTALLERS = 0x00000022,
+ DIF_ADDPROPERTYPAGE_ADVANCED = 0x00000023,
+ DIF_ADDPROPERTYPAGE_BASIC = 0x00000024,
+ DIF_RESERVED1 = 0x00000025,
+ DIF_TROUBLESHOOTER = 0x00000026,
+ DIF_POWERMESSAGEWAKE = 0x00000027,
+ DIF_ADDREMOTEPROPERTYPAGE_ADVANCED = 0x00000028,
+ DIF_UPDATEDRIVER_UI = 0x00000029,
+ DIF_FINISHINSTALL_ACTION = 0x0000002a,
+ }
+
+ [Flags]
+ public enum GetClassFlags : uint
+ {
+ DIGCF_DEFAULT = 0x00000001,
+ DIGCF_PRESENT = 0x00000002,
+ DIGCF_ALLCLASSES = 0x00000004,
+ DIGCF_PROFILE = 0x00000008,
+ DIGCF_DEVICEINTERFACE = 0x00000010,
+ }
+
+ [Flags]
+ public enum InstallFlags : uint
+ {
+ INSTALLFLAG_FORCE = 0x00000001,
+ INSTALLFLAG_READONLY = 0x00000002,
+ INSTALLFLAG_NONINTERACTIVE = 0x00000004,
+ INSTALLFLAG_BITS = 0x00000007,
+ }
+ }
+
+ public class NativeMethods
+ {
+ [DllImport("Setupapi.dll", SetLastError = true)]
+ public static extern bool SetupDiCallClassInstaller(
+ NativeHelpers.DifCodes InstallFunction,
+ SafeDeviceInfoSet DeviceInfoSet,
+ NativeHelpers.SP_DEVINFO_DATA DeviceInfoData);
+
+ [DllImport("Setupapi.dll", SetLastError = true)]
+ public static extern SafeDeviceInfoSet SetupDiCreateDeviceInfoList(
+ Guid ClassGuid,
+ IntPtr hwndParent);
+
+ [DllImport("Setupapi.dll", SetLastError = true)]
+ public static extern bool SetupDiCreateDeviceInfoW(
+ SafeDeviceInfoSet DeviceInfoSet,
+ [MarshalAs(UnmanagedType.LPWStr)] string DeviceName,
+ Guid ClassGuid,
+ [MarshalAs(UnmanagedType.LPWStr)] string DeviceDescription,
+ IntPtr hwndParent,
+ NativeHelpers.DeviceInfoCreationFlags CreationFlags,
+ NativeHelpers.SP_DEVINFO_DATA DeviceInfoData);
+
+ [DllImport("Setupapi.dll", SetLastError = true)]
+ public static extern bool SetupDiDestroyDeviceInfoList(
+ IntPtr DeviceInfoSet);
+
+ [DllImport("Setupapi.dll", SetLastError = true)]
+ public static extern bool SetupDiEnumDeviceInfo(
+ SafeDeviceInfoSet DeviceInfoSet,
+ UInt32 MemberIndex,
+ NativeHelpers.SP_DEVINFO_DATA DeviceInfoData);
+
+ [DllImport("Setupapi.dll", SetLastError = true)]
+ public static extern SafeDeviceInfoSet SetupDiGetClassDevsW(
+ Guid ClassGuid,
+ [MarshalAs(UnmanagedType.LPWStr)] string Enumerator,
+ IntPtr hwndParent,
+ NativeHelpers.GetClassFlags Flags);
+
+ [DllImport("Setupapi.dll", SetLastError = true)]
+ public static extern bool SetupDiGetDeviceRegistryPropertyW(
+ SafeDeviceInfoSet DeviceInfoSet,
+ NativeHelpers.SP_DEVINFO_DATA DeviceInfoData,
+ NativeHelpers.DeviceProperty Property,
+ out UInt32 PropertyRegDataType,
+ SafeMemoryBuffer PropertyBuffer,
+ UInt32 PropertyBufferSize,
+ ref UInt32 RequiredSize);
+
+ [DllImport("Setupapi.dll", SetLastError = true)]
+ public static extern bool SetupDiGetINFClassW(
+ [MarshalAs(UnmanagedType.LPWStr)] string InfName,
+ ref Guid ClassGuid,
+ [MarshalAs(UnmanagedType.LPWStr)] StringBuilder ClassName,
+ UInt32 ClassNameSize,
+ ref UInt32 RequiredSize);
+
+ [DllImport("Setupapi.dll", SetLastError = true)]
+ public static extern bool SetupDiSetDeviceRegistryPropertyW(
+ SafeDeviceInfoSet DeviceInfoSet,
+ NativeHelpers.SP_DEVINFO_DATA DeviceInfoData,
+ NativeHelpers.DeviceProperty Property,
+ SafeMemoryBuffer PropertyBuffer,
+ UInt32 PropertyBufferSize);
+
+ [DllImport("Newdev.dll", SetLastError = true)]
+ public static extern bool UpdateDriverForPlugAndPlayDevicesW(
+ IntPtr hwndParent,
+ [MarshalAs(UnmanagedType.LPWStr)] string HardwareId,
+ [MarshalAs(UnmanagedType.LPWStr)] string FullInfPath,
+ NativeHelpers.InstallFlags InstallFlags,
+ ref bool bRebootRequired);
+ }
+
+ public class SafeDeviceInfoSet : SafeHandleZeroOrMinusOneIsInvalid
+ {
+ public SafeDeviceInfoSet() : base(true) { }
+
+ [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
+ protected override bool ReleaseHandle()
+ {
+ return NativeMethods.SetupDiDestroyDeviceInfoList(handle);
+ }
+ }
+
+ public class SafeMemoryBuffer : SafeHandleZeroOrMinusOneIsInvalid
+ {
+ public int Length = 0;
+
+ public SafeMemoryBuffer() : base(true) { }
+
+ public SafeMemoryBuffer(int cb) : base(true)
+ {
+ Length = cb;
+ base.SetHandle(Marshal.AllocHGlobal(cb));
+ }
+
+ public SafeMemoryBuffer(string sz) : base(true)
+ {
+ Length = sz.Length * sizeof(char);
+ base.SetHandle(Marshal.StringToHGlobalUni(sz));
+ }
+
+ [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
+ protected override bool ReleaseHandle()
+ {
+ Marshal.FreeHGlobal(handle);
+ return true;
+ }
+ }
+
+ public class DeviceUtil
+ {
+ public static string GetDeviceFriendlyName(SafeDeviceInfoSet devInfoSet, NativeHelpers.SP_DEVINFO_DATA devInfo)
+ {
+ string friendlyName = GetDeviceStringProp(devInfoSet, devInfo, NativeHelpers.DeviceProperty.SPDRP_FRIENDLYNAME);
+
+ // Older Windows versions may not have a friendly name set. This seems to be the case when the device has
+ // a unique description so we fallback to that value.
+ if (null == friendlyName)
+ friendlyName = GetDeviceStringProp(devInfoSet, devInfo, NativeHelpers.DeviceProperty.SPDRP_DEVICEDESC);
+
+ return friendlyName;
+ }
+
+ public static void SetDeviceHardwareId(SafeDeviceInfoSet devInfoSet, NativeHelpers.SP_DEVINFO_DATA devInfo,
+ string hardwareId)
+ {
+ SetDeviceStringProp(devInfoSet, devInfo, NativeHelpers.DeviceProperty.SPDRP_HARDWAREID, hardwareId);
+ }
+
+ private static string GetDeviceStringProp(SafeDeviceInfoSet devInfoSet, NativeHelpers.SP_DEVINFO_DATA devInfo,
+ NativeHelpers.DeviceProperty property)
+ {
+ using (SafeMemoryBuffer memBuf = GetDeviceProperty(devInfoSet, devInfo, property))
+ {
+ if (memBuf.IsInvalid) // Property does not exist so just return null.
+ return null;
+
+ return Marshal.PtrToStringUni(memBuf.DangerousGetHandle());
+ }
+ }
+
+ private static SafeMemoryBuffer GetDeviceProperty(SafeDeviceInfoSet devInfoSet,
+ NativeHelpers.SP_DEVINFO_DATA devInfo, NativeHelpers.DeviceProperty property)
+ {
+ UInt32 requiredSize = 0;
+ UInt32 regDataType = 0;
+ if (!NativeMethods.SetupDiGetDeviceRegistryPropertyW(devInfoSet, devInfo, property,
+ out regDataType, new SafeMemoryBuffer(0), 0, ref requiredSize))
+ {
+ int errCode = Marshal.GetLastWin32Error();
+ if (errCode == 0x0000000D) // ERROR_INVALID_DATA
+ return new SafeMemoryBuffer(); // The FRIENDLYNAME property does not exist
+ else if (errCode != 0x0000007A) // ERROR_INSUFFICIENT_BUFFER
+ throw new Win32Exception(errCode);
+ }
+
+ SafeMemoryBuffer memBuf = new SafeMemoryBuffer((int)requiredSize);
+ if (!NativeMethods.SetupDiGetDeviceRegistryPropertyW(devInfoSet, devInfo, property,
+ out regDataType, memBuf, requiredSize, ref requiredSize))
+ {
+ int errCode = Marshal.GetLastWin32Error();
+ memBuf.Dispose();
+
+ throw new Win32Exception(errCode);
+ }
+
+ return memBuf;
+ }
+
+ private static void SetDeviceStringProp(SafeDeviceInfoSet devInfoSet, NativeHelpers.SP_DEVINFO_DATA devInfo,
+ NativeHelpers.DeviceProperty property, string value)
+ {
+ using (SafeMemoryBuffer buffer = new SafeMemoryBuffer(value))
+ SetDeviceProperty(devInfoSet, devInfo, property, buffer);
+ }
+
+ private static void SetDeviceProperty(SafeDeviceInfoSet devInfoSet, NativeHelpers.SP_DEVINFO_DATA devInfo,
+ NativeHelpers.DeviceProperty property, SafeMemoryBuffer buffer)
+ {
+ if (!NativeMethods.SetupDiSetDeviceRegistryPropertyW(devInfoSet, devInfo, property, buffer,
+ (UInt32)buffer.Length))
+ {
+ throw new Win32Exception(Marshal.GetLastWin32Error());
+ }
+ }
+ }
+}
+'@
+
+Function Get-Win32ErrorMessage {
+ Param ([System.Int32]$ErrorCode)
+
+ $exp = New-Object -TypeName System.ComponentModel.Win32Exception -ArgumentList $ErrorCode
+ return ("{0} (Win32 ErrorCode {1} - 0x{1:X8}" -f $exp.Message, $ErrorCode)
+}
+
+# Determine if the device is already installed
+$dev_info_set = [Ansible.Device.NativeMethods]::SetupDiGetClassDevsW(
+ [Guid]::Empty,
+ [NullString]::Value,
+ [System.IntPtr]::Zero,
+ [Ansible.Device.NativeHelpers+GetClassFlags]::DIGCF_ALLCLASSES
+); $err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
+
+try {
+ if ($dev_info_set.IsInvalid) {
+ $msg = Get-Win32ErrorMessage -ErrorCode $err
+ $module.FailJson("Failed to get device information set for installed devices: $msg")
+ }
+
+ $dev_info = $null
+ if ($null -ne $name) {
+ # Loop through the set of all devices and compare the name
+ $idx = 0
+ while ($true) {
+ $dev_info = New-Object -TypeName Ansible.Device.NativeHelpers+SP_DEVINFO_DATA
+ $res = [Ansible.Device.NativeMethods]::SetupDiEnumDeviceInfo(
+ $dev_info_set,
+ $idx,
+ $dev_info
+ ); $err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
+
+ if (-not $res) {
+ $dev_info = $null
+ if ($err -eq 0x00000103) {
+ # ERROR_NO_MORE_ITEMS
+ break
+ }
+
+ $msg = Get-Win32ErrorMessage -ErrorCode $err
+ $module.FailJson("Failed to enumerate device information set at index $($idx): $msg")
+ }
+
+ $device_name = [Ansible.Device.DeviceUtil]::GetDeviceFriendlyName($dev_info_set, $dev_info)
+ if ($device_name -eq $name) {
+ break
+ }
+
+ $dev_info = $null
+ $idx++
+ }
+ }
+
+ if ($state -eq "absent" -and $null -ne $dev_info) {
+ if (-not $module.CheckMode) {
+ $res = [Ansible.Device.NativeMethods]::SetupDiCallClassInstaller(
+ [Ansible.Device.NativeHelpers+DifCodes]::DIF_REMOVE,
+ $dev_info_set,
+ $dev_info
+ ); $err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
+
+ if (-not $res) {
+ $msg = Get-Win32ErrorMessage -ErrorCode $err
+ $module.FailJson("Failed to remove device $($name): $msg")
+ }
+ }
+
+ $module.Result.changed = $true
+ }
+ elseif ($state -eq "present" -and $null -eq $dev_info) {
+ # Populate the class guid and display name if the path to an inf file was set.
+ $class_id = [Guid]::Empty
+ $class_name = $null
+ if ($path) {
+ if (-not (Test-Path -LiteralPath $path)) {
+ $module.FailJson("Could not find the inf file specified at '$path'")
+ }
+
+ $class_name_sb = New-Object -TypeName System.Text.StringBuilder -ArgumentList 32 # MAX_CLASS_NAME_LEN
+ $required_size = 0
+ $res = [Ansible.Device.NativeMethods]::SetupDiGetINFClassW(
+ $path,
+ [ref]$class_id,
+ $class_name_sb,
+ $class_name_sb.Capacity,
+ [ref]$required_size
+ ); $err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
+
+ if (-not $res) {
+ $msg = Get-Win32ErrorMessage -ErrorCode $err
+ $module.FailJson("Failed to parse driver inf at '$path': $msg")
+ }
+
+ $class_name = $class_name_sb.ToString()
+ }
+
+ # When creating a new device we want to start with a blank device information set.
+ $dev_info_set.Dispose()
+
+ $dev_info_set = [Ansible.Device.NativeMethods]::SetupDiCreateDeviceInfoList(
+ $class_id,
+ [System.IntPtr]::Zero
+ ); $err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
+
+ if ($dev_info_set.IsInvalid) {
+ $msg = Get-Win32ErrorMessage -ErrorCode $err
+ $module.FailJson("Failed to create device info set for the class $($class_id): $msg")
+ }
+
+ # Create the new device element and add it to the device info set
+ $dev_info = New-Object -TypeName Ansible.Device.NativeHelpers+SP_DEVINFO_DATA
+ $res = [Ansible.Device.NativeMethods]::SetupDiCreateDeviceInfoW(
+ $dev_info_set,
+ $class_name,
+ $class_id,
+ $null,
+ [System.IntPtr]::Zero,
+ [Ansible.Device.NativeHelpers+DeviceInfoCreationFlags]::DICD_GENERATE_ID,
+ $dev_info
+ ); $err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
+
+ if (-not $res) {
+ $msg = Get-Win32ErrorMessage -ErrorCode $err
+ $module.FailJson("Failed to create new device element for class $($class_name): $msg")
+ }
+
+ # Set the hardware id of the new device so we can load the proper driver.
+ [Ansible.Device.DeviceUtil]::SetDeviceHardwareId($dev_info_set, $dev_info, $hardware_id)
+
+ if (-not $module.CheckMode) {
+ # Install the device
+ $res = [Ansible.Device.NativeMethods]::SetupDiCallClassInstaller(
+ [Ansible.Device.NativeHelpers+DifCodes]::DIF_REGISTERDEVICE,
+ $dev_info_set,
+ $dev_info
+ ); $err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
+
+ if (-not $res) {
+ $msg = Get-Win32ErrorMessage -ErrorCode $err
+ $module.FailJson("Failed to register new device for class $($class_name): $msg")
+ }
+
+ # Load the drivers for the new device
+ $reboot_required = $false
+ $res = [Ansible.Device.NativeMethods]::UpdateDriverForPlugAndPlayDevicesW(
+ [System.IntPtr]::Zero,
+ $hardware_id,
+ $path,
+ [Ansible.Device.NativeHelpers+InstallFlags]'INSTALLFLAG_FORCE, INSTALLFLAG_NONINTERACTIVE',
+ [ref]$reboot_required
+ ); $err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
+
+ if (-not $res) {
+ # On a failure make sure we cleanup the "installed" device
+ [Ansible.Device.NativeMethods]::SetupDiCallClassInstaller(
+ [Ansible.Device.NativeHelpers+DifCodes]::DIF_REMOVE,
+ $dev_info_set,
+ $dev_info
+ ) > $null
+
+ $msg = Get-Win32ErrorMessage -ErrorCode $err
+ $module.FailJson("Failed to update device driver: $msg")
+ }
+
+ $module.Result.reboot_required = $reboot_required
+
+ # Now get the name of the newly created device which we return back to Ansible.
+ $name = [Ansible.Device.DeviceUtil]::GetDeviceFriendlyName($dev_info_set, $dev_info)
+ }
+ else {
+ # Generate random name for check mode output
+ $name = "Check mode generated device for $($class_name)"
+ }
+ $module.Result.changed = $true
+ }
+}
+finally {
+ $dev_info_set.Dispose()
+}
+
+$module.Result.name = $name
+
+$module.ExitJson()
+
diff --git a/ansible_collections/community/windows/tests/integration/targets/setup_win_device/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/setup_win_device/tasks/main.yml
new file mode 100644
index 000000000..9bfe36fcf
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/setup_win_device/tasks/main.yml
@@ -0,0 +1,22 @@
+# Creates a network adapter device for testing purposes and registers the following vars
+# network_device_name: The name of the network device
+# network_adapter_name: The name of the network adapter
+---
+- name: create dummy network adapter device
+ win_device:
+ path: '%WinDir%\Inf\netloop.inf'
+ hardware_id: '*msloop'
+ state: present
+ register: network_device_name_raw
+ notify: remove dummy network adapter device
+
+- set_fact:
+ network_device_name: '{{ network_device_name_raw.name }}'
+
+- name: get name of the dummy network adapter
+ ansible.windows.win_shell: (Get-CimInstance -Class Win32_NetworkAdapter -Filter "Name='{{ network_device_name }}'").NetConnectionID
+ changed_when: False
+ register: network_adapter_name_raw
+
+- set_fact:
+ network_adapter_name: '{{ network_adapter_name_raw.stdout | trim }}'
diff --git a/ansible_collections/community/windows/tests/integration/targets/setup_win_psget/meta/main.yml b/ansible_collections/community/windows/tests/integration/targets/setup_win_psget/meta/main.yml
new file mode 100644
index 000000000..45806c8dc
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/setup_win_psget/meta/main.yml
@@ -0,0 +1,2 @@
+dependencies:
+- setup_remote_tmp_dir \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/setup_win_psget/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/setup_win_psget/tasks/main.yml
new file mode 100644
index 000000000..ce1607647
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/setup_win_psget/tasks/main.yml
@@ -0,0 +1,129 @@
+# Installs PackageManagement and PowerShellGet to the required versions for testing
+---
+- name: check if PackageManagement has been installed
+ ansible.windows.win_powershell:
+ script: |
+ $ErrorActionPreference = 'Stop'
+ $Ansible.Changed = $false
+
+ if (-not (Get-Command -Name Install-Module -ErrorAction SilentlyContinue)) {
+ [PSCustomObject]@{
+ Install = $true
+ Action = "scratch"
+ }
+ return
+ }
+
+ $psGet = Get-Module -Name PowerShellGet -ListAvailable |
+ Sort-Object -Property Version -Descending |
+ Select-Object -First 1 -ExpandProperty Version
+ $package = Get-Module -Name PackageManagement -ListAvailable |
+ Sort-Object -Property Version -Descending |
+ Select-Object -First 1 -ExpandProperty Version
+
+ if ($psGet -lt [Version]"1.6.0" -or $package -lt [Version]"1.1.7") {
+ [PSCustomObject]@{
+ Install = $true
+ Action = "module"
+ }
+ }
+ else {
+ [PSCustomObject]@{
+ Install = $false
+ }
+ }
+
+ register: module_installed
+
+- name: bootstrap required modules
+ when: module_installed.output[0].Install
+ block:
+ - name: install PackageManagement for older hosts
+ ansible.windows.win_package:
+ path: https://ansible-ci-files.s3.amazonaws.com/test/integration/targets/setup_win_psget/PackageManagement_x64.msi
+ product_id: '{57E5A8BB-41EB-4F09-B332-B535C5954A28}'
+ state: present
+ when: module_installed.output[0].Action == "scratch"
+ register: download_res
+ until: download_res is successful
+ retries: 3
+ delay: 5
+
+ - name: remove the old versions of PackageManagement and PowerShellGet
+ ansible.windows.win_file:
+ path: C:\Program Files\WindowsPowerShell\Modules\{{ item }}
+ state: absent
+ when: module_installed.output[0].Action == "scratch"
+ loop:
+ - PackageManagement
+ - PowerShellGet
+
+ - name: create the required folder for nuget
+ ansible.windows.win_file:
+ path: C:\Program Files\PackageManagement\ProviderAssemblies\nuget\2.8.5.208
+ state: directory
+
+ - name: download nuget provider dll
+ ansible.windows.win_get_url:
+ url: https://ansible-ci-files.s3.amazonaws.com/test/integration/targets/setup_win_psget/Microsoft.PackageManagement.NuGetProvider-2.8.5.208.dll
+ dest: C:\Program Files\PackageManagement\ProviderAssemblies\nuget\2.8.5.208\Microsoft.PackageManagement.NuGetProvider.dll
+ force: false
+ register: nuget_download_res
+ until: nuget_download_res is successful
+ retries: 3
+ delay: 5
+
+ - name: download newer PackageManagement and PowerShellGet nupkg
+ ansible.windows.win_get_url:
+ url: '{{ item.url }}'
+ dest: '{{ remote_tmp_dir }}\{{ item.name }}.{{ "nupkg" if module_installed.output[0].Action == "module" else "zip" }}' # .zip is required for win_unzip
+ when: module_installed.output[0].Install
+ register: download_res
+ until: download_res is successful
+ retries: 3
+ delay: 5
+ loop:
+ - name: PackageManagement
+ url: https://ansible-ci-files.s3.amazonaws.com/test/integration/targets/setup_win_psget/packagemanagement.1.1.7.nupkg
+ - name: PowerShellGet
+ url: https://ansible-ci-files.s3.amazonaws.com/test/integration/targets/setup_win_psget/powershellget.1.6.0.nupkg
+
+ - name: extract new modules to correct location for older hosts
+ win_unzip:
+ src: '{{ remote_tmp_dir }}\{{ item }}.zip'
+ dest: C:\Program Files\WindowsPowerShell\Modules\{{ item }}
+ when: module_installed.output[0].Action == "scratch"
+ loop:
+ - PackageManagement
+ - PowerShellGet
+
+ - name: update PackageManagement and PowerShellGet
+ when: module_installed.output[0].Action == "module"
+ block:
+ - name: register local PSRepo
+ ansible.windows.win_powershell:
+ script: |
+ param($Path)
+
+ Register-PSRepository -Name LocalNuget -SourceLocation $Path
+ parameters:
+ Path: '{{ remote_tmp_dir }}'
+
+ - name: ensure PowerShellGet and PackageManagement requirements have been met
+ win_psmodule:
+ name: PowerShellGet
+ repository: LocalNuget
+ accept_license: true
+ state: present
+
+ always:
+ - name: unregister local PSRepo
+ ansible.windows.win_powershell:
+ script: |
+ if (Get-PSRepository -Name LocalNuget -ErrorAction SilentlyContinue) {
+ Unregister-PSRepository -Name LocalNuget
+ $Ansible.Changed = $true
+ }
+ else {
+ $Ansible.Changed = $false
+ }
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_audit_policy_system/aliases b/ansible_collections/community/windows/tests/integration/targets/win_audit_policy_system/aliases
new file mode 100644
index 000000000..3cf5b97e8
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_audit_policy_system/aliases
@@ -0,0 +1 @@
+shippable/windows/group3
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_audit_policy_system/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_audit_policy_system/defaults/main.yml
new file mode 100644
index 000000000..9e0d35c77
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_audit_policy_system/defaults/main.yml
@@ -0,0 +1,3 @@
+#important that the subcategory is from a different category
+category_name: detailed tracking
+subcategory_name: file system
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_audit_policy_system/tasks/add.yml b/ansible_collections/community/windows/tests/integration/targets/win_audit_policy_system/tasks/add.yml
new file mode 100644
index 000000000..75ea23045
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_audit_policy_system/tasks/add.yml
@@ -0,0 +1,108 @@
+########################
+### check mode apply ###
+########################
+- name: check mode enable category
+ win_audit_policy_system:
+ category: "{{ category_name }}"
+ audit_type: success
+ check_mode: yes
+ register: category
+
+- name: check mode enable subcategory
+ win_audit_policy_system:
+ subcategory: "{{ subcategory_name }}"
+ audit_type: success, failure
+ check_mode: yes
+ register: subcategory
+
+- name: check mode assert that changed is true
+ assert:
+ that:
+ - category is changed
+ - subcategory is changed
+
+- name: check mode assert that audit_type is "no auditing"
+ assert:
+ that:
+ - item == "no auditing"
+ with_items:
+ - "{{ subcategory.current_audit_policy.values() | list }}"
+ - "{{ category.current_audit_policy.values() | list | unique }}"
+
+#alternative check for category...pretty noise and requires more lines
+# - name: assert that audit_type is no auditing
+# assert:
+# that: item.value == "no auditing"
+# with_dict: "{{ category.current_audit_policy }}"
+
+####################
+### apply change ###
+####################
+
+- name: enable category
+ win_audit_policy_system:
+ category: "{{ category_name }}"
+ audit_type: success
+ register: category
+
+- name: enable subcategory
+ win_audit_policy_system:
+ subcategory: "{{ subcategory_name }}"
+ audit_type: success, failure
+ register: subcategory
+
+- name: enable assert that changed is true
+ assert:
+ that:
+ - category is changed
+ - subcategory is changed
+
+- name: enable assert that audit_type is "success" for category
+ assert:
+ that:
+ - item == "success"
+ with_items:
+ - "{{ category.current_audit_policy.values() | list | unique }}"
+
+- name: enable assert that audit_type is "success and failure" for subcategory
+ assert:
+ that:
+ - item == "success and failure"
+ with_items:
+ - "{{ subcategory.current_audit_policy.values() | list }}"
+
+###############################
+### idempotent apply change ###
+###############################
+
+- name: idem enable category
+ win_audit_policy_system:
+ category: "{{ category_name }}"
+ audit_type: success
+ register: category
+
+- name: idem enable subcategory
+ win_audit_policy_system:
+ subcategory: "{{ subcategory_name }}"
+ audit_type: success, failure
+ register: subcategory
+
+- name: idem assert that changed is false
+ assert:
+ that:
+ - category is not changed
+ - subcategory is not changed
+
+- name: idem assert that audit_type is "success" for category
+ assert:
+ that:
+ - item == "success"
+ with_items:
+ - "{{ category.current_audit_policy.values() | list | unique }}"
+
+- name: idem assert that audit_type is "success and failure" for subcategory
+ assert:
+ that:
+ - item == "success and failure"
+ with_items:
+ - "{{ subcategory.current_audit_policy.values() | list }}"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_audit_policy_system/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_audit_policy_system/tasks/main.yml
new file mode 100644
index 000000000..c2e55accf
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_audit_policy_system/tasks/main.yml
@@ -0,0 +1,25 @@
+#turn off so then we can test changes occur on enable. Turning off for object access also
+#covers our subcategory test for file system
+- name: turn off auditing for category
+ win_audit_policy_system:
+ category: "{{ category_name }}"
+ audit_type: none
+
+- name: turn off auditing for subcategory
+ win_audit_policy_system:
+ subcategory: "{{ subcategory_name }}"
+ audit_type: none
+
+- block:
+ - include_tasks: add.yml
+ - include_tasks: remove.yml
+ always:
+ - name: CLEANUP turn "{{ category_name }}" back to no auditing
+ win_audit_policy_system:
+ category: "{{ category_name }}"
+ audit_type: none
+
+ - name: CLEANUP turn "{{ subcategory_name }}" back to no auditing
+ win_audit_policy_system:
+ subcategory: "{{ subcategory_name }}"
+ audit_type: none
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_audit_policy_system/tasks/remove.yml b/ansible_collections/community/windows/tests/integration/targets/win_audit_policy_system/tasks/remove.yml
new file mode 100644
index 000000000..1cd60b0ab
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_audit_policy_system/tasks/remove.yml
@@ -0,0 +1,96 @@
+#########################
+### check mode remove ###
+#########################
+- name: check mode disable category
+ win_audit_policy_system:
+ category: "{{ category_name }}"
+ audit_type: none
+ check_mode: yes
+ register: category
+
+- name: check mode disable subcategory
+ win_audit_policy_system:
+ subcategory: "{{ subcategory_name }}"
+ audit_type: none
+ check_mode: yes
+ register: subcategory
+
+- name: check mode assert that changed is true
+ assert:
+ that:
+ - category is changed
+ - subcategory is changed
+
+- name: check mode assert that audit_type is still "success" (old value) for category
+ assert:
+ that:
+ - item == "success"
+ with_items:
+ - "{{ category.current_audit_policy.values() | list | unique }}"
+
+- name: check mode assert that audit_type is still "success and failure" (old value) for subcategory
+ assert:
+ that:
+ - item == "success and failure"
+ with_items:
+ - "{{ subcategory.current_audit_policy.values() | list }}"
+
+######################
+### disable policy ###
+######################
+
+- name: disable category
+ win_audit_policy_system:
+ category: "{{ category_name }}"
+ audit_type: none
+ register: category
+
+- name: disable subcategory
+ win_audit_policy_system:
+ subcategory: "{{ subcategory_name }}"
+ audit_type: none
+ register: subcategory
+
+- name: assert that changed is true
+ assert:
+ that:
+ - category is changed
+ - subcategory is changed
+
+- name: assert that audit_type is "no auditing"
+ assert:
+ that:
+ - item == "no auditing"
+ with_items:
+ - "{{ subcategory.current_audit_policy.values() | list }}"
+ - "{{ category.current_audit_policy.values() | list | unique }}"
+
+##########################
+### idempotent disable ###
+##########################
+
+- name: idem disable category
+ win_audit_policy_system:
+ category: "{{ category_name }}"
+ audit_type: none
+ register: category
+
+- name: idem disable subcategory
+ win_audit_policy_system:
+ subcategory: "{{ subcategory_name }}"
+ audit_type: none
+ register: subcategory
+
+- name: idem assert that changed is false
+ assert:
+ that:
+ - category is not changed
+ - subcategory is not changed
+
+- name: assert that audit_type is "no auditing"
+ assert:
+ that:
+ - item == "no auditing"
+ with_items:
+ - "{{ subcategory.current_audit_policy.values() | list }}"
+ - "{{ category.current_audit_policy.values() | list | unique }}"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_audit_rule/aliases b/ansible_collections/community/windows/tests/integration/targets/win_audit_rule/aliases
new file mode 100644
index 000000000..423ce3910
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_audit_rule/aliases
@@ -0,0 +1 @@
+shippable/windows/group2
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_audit_rule/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_audit_rule/defaults/main.yml
new file mode 100644
index 000000000..f0faa9a56
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_audit_rule/defaults/main.yml
@@ -0,0 +1,7 @@
+test_audit_rule_folder: c:\windows\temp\{{ 'ansible test win_audit_policy' | to_uuid }}
+test_audit_rule_file: c:\windows\temp\{{ 'ansible test win_audit_policy' | to_uuid }}.txt
+test_audit_rule_registry: HKCU:\{{ 'ansible test win_audit_policy' | to_uuid }}
+test_audit_rule_rights: 'delete'
+test_audit_rule_new_rights: 'delete,changepermissions'
+test_audit_rule_user: 'everyone'
+test_audit_rule_audit_flags: success
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_audit_rule/library/test_get_audit_rule.ps1 b/ansible_collections/community/windows/tests/integration/targets/win_audit_rule/library/test_get_audit_rule.ps1
new file mode 100644
index 000000000..37096c21a
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_audit_rule/library/test_get_audit_rule.ps1
@@ -0,0 +1,93 @@
+#!powershell
+
+# Copyright (c) 2017 Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#Requires -Module Ansible.ModuleUtils.Legacy
+#Requires -Module Ansible.ModuleUtils.SID
+
+$params = Parse-Args -arguments $args -supports_check_mode $true
+
+# these are your module parameters
+$path = Get-AnsibleParam -obj $params -name "path" -type "path" -failifempty $true -aliases "destination", "dest"
+$user = Get-AnsibleParam -obj $params -name "user" -type "str" -failifempty $true
+$rights = Get-AnsibleParam -obj $params -name "rights" -type "list"
+$inheritance_flags = Get-AnsibleParam -obj $params -name "inheritance_flags" -type "list" -default 'ContainerInherit', 'ObjectInherit'
+$propOptions = 'InheritOnly', 'None', 'NoPropagateInherit'
+$propagation_flags = Get-AnsibleParam -obj $params -name "propagation_flags" -type "str" -default "none" -ValidateSet $propOptions
+$audit_flags = Get-AnsibleParam -obj $params -name "audit_flags" -type "list" -default "success" #-ValidateSet 'Success','Failure'
+#$state = Get-AnsibleParam -obj $params -name "state" -type "str" -default "present" -validateset 'present','absent'
+
+
+If (! (Test-Path $path) ) {
+ Fail-Json $result "Path not found ($path)"
+}
+
+Function Get-CurrentAuditRule ($path) {
+ $ACL = Get-Acl -Path $path -Audit
+
+ $HT = Foreach ($Obj in $ACL.Audit) {
+ @{
+ user = $Obj.IdentityReference.ToString()
+ rights = ($Obj | Select-Object -expand "*rights").ToString()
+ audit_flags = $Obj.AuditFlags.ToString()
+ is_inherited = $Obj.InheritanceFlags.ToString()
+ inheritance_flags = $Obj.IsInherited.ToString()
+ propagation_flags = $Obj.PropagationFlags.ToString()
+ }
+ }
+
+ If (-Not $HT) {
+ "No audit rules defined on $path"
+ }
+ Else { $HT }
+}
+
+
+$result = @{
+ changed = $false
+ matching_rule_found = $false
+ current_audit_rules = Get-CurrentAuditRule $path
+}
+
+$ACL = Get-ACL $Path -Audit
+$SID = Convert-ToSid $user
+
+$ItemType = (Get-Item $path).GetType()
+switch ($ItemType) {
+ ([Microsoft.Win32.RegistryKey]) {
+ $rights = [System.Security.AccessControl.RegistryRights]$rights
+ $result.path_type = 'registry'
+ }
+ ([System.IO.FileInfo]) {
+ $rights = [System.Security.AccessControl.FileSystemRights]$rights
+ $result.path_type = 'file'
+ }
+ ([System.IO.DirectoryInfo]) {
+ $rights = [System.Security.AccessControl.FileSystemRights]$rights
+ $result.path_type = 'directory'
+ }
+}
+
+$flags = [System.Security.AccessControl.AuditFlags]$audit_flags
+$inherit = [System.Security.AccessControl.InheritanceFlags]$inheritance_flags
+$prop = [System.Security.AccessControl.PropagationFlags]$propagation_flags
+
+Foreach ($group in $ACL.Audit) {
+ #exit here if any existing rule matches defined rule, otherwise exit below
+ #with no matches
+ If (
+ ($group | Select-Object -expand "*Rights") -eq $rights -and
+ $group.AuditFlags -eq $flags -and
+ $group.IdentityReference.Translate([System.Security.Principal.SecurityIdentifier]) -eq $SID -and
+ $group.InheritanceFlags -eq $inherit -and
+ $group.PropagationFlags -eq $prop
+ ) {
+ $result.matching_rule_found = $true
+ $result.current_audit_rules = Get-CurrentAuditRule $path
+ Exit-Json $result
+ }
+}
+
+$result.current_audit_rules = Get-CurrentAuditRule $path
+Exit-Json $result
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_audit_rule/tasks/add.yml b/ansible_collections/community/windows/tests/integration/targets/win_audit_rule/tasks/add.yml
new file mode 100644
index 000000000..2a059a88c
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_audit_rule/tasks/add.yml
@@ -0,0 +1,172 @@
+######################
+### check mode add ###
+######################
+- name: check mode ADD audit policy directory
+ win_audit_rule:
+ path: "{{ test_audit_rule_folder }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_rights }}"
+ state: present
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ register: directory
+ check_mode: yes
+
+- name: check mode ADD audit policy file
+ win_audit_rule:
+ path: "{{ test_audit_rule_file }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_rights }}"
+ state: present
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ inheritance_flags: none
+ register: file
+ check_mode: yes
+
+- name: check mode ADD audit policy registry
+ win_audit_rule:
+ path: "{{ test_audit_rule_registry }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_rights }}"
+ state: present
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ register: registry
+ check_mode: yes
+
+- name: check mode ADD get directory results
+ test_get_audit_rule:
+ path: "{{ test_audit_rule_folder }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_rights }}"
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ register: directory_results
+
+- name: check mode ADD get file results
+ test_get_audit_rule:
+ path: "{{ test_audit_rule_file }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_rights }}"
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ inheritance_flags: none
+ register: file_results
+
+- name: check mode ADD get REGISTRY results
+ test_get_audit_rule:
+ path: "{{ test_audit_rule_registry }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_rights }}"
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ register: registry_results
+
+- name: check mode ADD assert that a change is needed, but no change occurred to the audit rules
+ assert:
+ that:
+ - directory is changed
+ - file is changed
+ - registry is changed
+ - not directory_results.matching_rule_found and directory_results.path_type == 'directory'
+ - not file_results.matching_rule_found and file_results.path_type == 'file'
+ - not registry_results.matching_rule_found and registry_results.path_type == 'registry'
+
+##################
+### add a rule ###
+##################
+- name: ADD audit policy directory
+ win_audit_rule:
+ path: "{{ test_audit_rule_folder }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_rights }}"
+ state: present
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ register: directory
+
+- name: ADD audit policy file
+ win_audit_rule:
+ path: "{{ test_audit_rule_file }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_rights }}"
+ state: present
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ inheritance_flags: none
+ register: file
+
+- name: ADD audit policy registry
+ win_audit_rule:
+ path: "{{ test_audit_rule_registry }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_rights }}"
+ state: present
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ register: registry
+
+- name: ADD get directory results
+ test_get_audit_rule:
+ path: "{{ test_audit_rule_folder }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_rights }}"
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ register: directory_results
+
+- name: ADD get file results
+ test_get_audit_rule:
+ path: "{{ test_audit_rule_file }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_rights }}"
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ inheritance_flags: none
+ register: file_results
+
+- name: ADD get REGISTRY results
+ test_get_audit_rule:
+ path: "{{ test_audit_rule_registry }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_rights }}"
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ register: registry_results
+
+- name: ADD assert that the rules were added and a change is detected
+ assert:
+ that:
+ - directory is changed
+ - file is changed
+ - registry is changed
+ - directory_results.matching_rule_found and directory_results.path_type == 'directory'
+ - file_results.matching_rule_found and file_results.path_type == 'file'
+ - registry_results.matching_rule_found and registry_results.path_type == 'registry'
+
+#############################
+### idempotent add a rule ###
+#############################
+- name: idempotent ADD audit policy directory
+ win_audit_rule:
+ path: "{{ test_audit_rule_folder }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_rights }}"
+ state: present
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ register: directory
+
+- name: idempotent ADD audit policy file
+ win_audit_rule:
+ path: "{{ test_audit_rule_file }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_rights }}"
+ state: present
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ inheritance_flags: none
+ register: file
+
+- name: idempotent ADD audit policy registry idempotent
+ win_audit_rule:
+ path: "{{ test_audit_rule_registry }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_rights }}"
+ state: present
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ register: registry
+
+- name: idempotent ADD assert that a change did not occur
+ assert:
+ that:
+ - directory is not changed and directory.path_type == 'directory'
+ - file is not changed and file.path_type == 'file'
+ - registry is not changed and registry.path_type == 'registry'
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_audit_rule/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_audit_rule/tasks/main.yml
new file mode 100644
index 000000000..cdeff7a3a
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_audit_rule/tasks/main.yml
@@ -0,0 +1,33 @@
+- name: create temporary folder to test with
+ ansible.windows.win_file:
+ path: "{{ test_audit_rule_folder }}"
+ state: directory
+
+- name: create temporary file to test with
+ ansible.windows.win_file:
+ path: "{{ test_audit_rule_file }}"
+ state: touch
+
+- name: create temporary registry key to test with
+ ansible.windows.win_regedit:
+ path: "{{ test_audit_rule_registry }}"
+
+- block:
+ - include_tasks: add.yml
+ - include_tasks: modify.yml
+ - include_tasks: remove.yml
+ always:
+ - name: remove testing folder
+ ansible.windows.win_file:
+ path: "{{ test_audit_rule_folder }}"
+ state: absent
+
+ - name: remove testing file
+ ansible.windows.win_file:
+ path: "{{ test_audit_rule_file }}"
+ state: absent
+
+ - name: remove registry key
+ ansible.windows.win_regedit:
+ path: "{{ test_audit_rule_registry }}"
+ state: absent
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_audit_rule/tasks/modify.yml b/ansible_collections/community/windows/tests/integration/targets/win_audit_rule/tasks/modify.yml
new file mode 100644
index 000000000..1db07e2b4
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_audit_rule/tasks/modify.yml
@@ -0,0 +1,172 @@
+#########################
+### modify check mode ###
+#########################
+- name: check mode modify audit policy directory
+ win_audit_rule:
+ path: "{{ test_audit_rule_folder }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_new_rights }}"
+ state: present
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ register: directory
+ check_mode: yes
+
+- name: check mode modify audit policy file
+ win_audit_rule:
+ path: "{{ test_audit_rule_file }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_new_rights }}"
+ state: present
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ inheritance_flags: none
+ register: file
+ check_mode: yes
+
+- name: check mode modify audit policy registry
+ win_audit_rule:
+ path: "{{ test_audit_rule_registry }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_new_rights }}"
+ state: present
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ register: registry
+ check_mode: yes
+
+- name: check mode modify get directory rule results
+ test_get_audit_rule:
+ path: "{{ test_audit_rule_folder }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_new_rights }}"
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ register: directory_results
+
+- name: check mode modify get file rule results
+ test_get_audit_rule:
+ path: "{{ test_audit_rule_file }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_new_rights }}"
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ inheritance_flags: none
+ register: file_results
+
+- name: check mode modify get REGISTRY rule results
+ test_get_audit_rule:
+ path: "{{ test_audit_rule_registry }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_new_rights }}"
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ register: registry_results
+
+- name: check mode modify assert that change is needed but rights still equal the original rights and not test_audit_rule_new_rights
+ assert:
+ that:
+ - directory is changed
+ - file is changed
+ - registry is changed
+ - not directory_results.matching_rule_found and directory_results.path_type == 'directory'
+ - not file_results.matching_rule_found and file_results.path_type == 'file'
+ - not registry_results.matching_rule_found and registry_results.path_type == 'registry'
+
+##############
+### modify ###
+##############
+- name: modify audit policy directory
+ win_audit_rule:
+ path: "{{ test_audit_rule_folder }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_new_rights }}"
+ state: present
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ register: directory
+
+- name: modify audit policy file
+ win_audit_rule:
+ path: "{{ test_audit_rule_file }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_new_rights }}"
+ state: present
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ inheritance_flags: none
+ register: file
+
+- name: modify audit policy registry
+ win_audit_rule:
+ path: "{{ test_audit_rule_registry }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_new_rights }}"
+ state: present
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ register: registry
+
+- name: modify get directory rule results
+ test_get_audit_rule:
+ path: "{{ test_audit_rule_folder }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_new_rights }}"
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ register: directory_results
+
+- name: modify get file rule results
+ test_get_audit_rule:
+ path: "{{ test_audit_rule_file }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_new_rights }}"
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ inheritance_flags: none
+ register: file_results
+
+- name: modify get REGISTRY rule results
+ test_get_audit_rule:
+ path: "{{ test_audit_rule_registry }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_new_rights }}"
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ register: registry_results
+
+- name: modify assert that the rules were modified and a change is detected
+ assert:
+ that:
+ - directory is changed
+ - file is changed
+ - registry is changed
+ - directory_results.matching_rule_found and directory_results.path_type == 'directory'
+ - file_results.matching_rule_found and file_results.path_type == 'file'
+ - registry_results.matching_rule_found and registry_results.path_type == 'registry'
+
+#####################################
+### idempotent test modify a rule ###
+#####################################
+- name: idempotent modify audit policy directory
+ win_audit_rule:
+ path: "{{ test_audit_rule_folder }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_new_rights }}"
+ state: present
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ register: directory
+
+- name: idempotent modify audit policy file
+ win_audit_rule:
+ path: "{{ test_audit_rule_file }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_new_rights }}"
+ state: present
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ inheritance_flags: none
+ register: file
+
+- name: idempotent modify audit policy registry
+ win_audit_rule:
+ path: "{{ test_audit_rule_registry }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_new_rights }}"
+ state: present
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ register: registry
+
+- name: idempotent modify assert that and a change is not detected
+ assert:
+ that:
+ - directory is not changed and directory.path_type == 'directory'
+ - file is not changed and file.path_type == 'file'
+ - registry is not changed and registry.path_type == 'registry'
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_audit_rule/tasks/remove.yml b/ansible_collections/community/windows/tests/integration/targets/win_audit_rule/tasks/remove.yml
new file mode 100644
index 000000000..3102bc748
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_audit_rule/tasks/remove.yml
@@ -0,0 +1,151 @@
+################################
+### check mode remove a rule ###
+################################
+- name: check mode remove directory rule
+ win_audit_rule:
+ path: "{{ test_audit_rule_folder }}"
+ user: "{{ test_audit_rule_user }}"
+ state: absent
+ register: directory
+ check_mode: yes
+
+- name: check mode remove file rule
+ win_audit_rule:
+ path: "{{ test_audit_rule_file }}"
+ user: "{{ test_audit_rule_user }}"
+ state: absent
+ register: file
+ check_mode: yes
+
+- name: check mode remove registry rule
+ win_audit_rule:
+ path: "{{ test_audit_rule_registry }}"
+ user: "{{ test_audit_rule_user }}"
+ state: absent
+ register: registry
+ check_mode: yes
+
+- name: check mode remove get directory rule results
+ test_get_audit_rule:
+ path: "{{ test_audit_rule_folder }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_new_rights }}"
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ register: directory_results
+
+- name: check mode remove get file rule results
+ test_get_audit_rule:
+ path: "{{ test_audit_rule_file }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_new_rights }}"
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ inheritance_flags: none
+ register: file_results
+
+- name: check mode remove get REGISTRY rule results
+ test_get_audit_rule:
+ path: "{{ test_audit_rule_registry }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_new_rights }}"
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ register: registry_results
+
+- name: check mode remove assert that change detected, but rule is still present
+ assert:
+ that:
+ - directory is changed
+ - file is changed
+ - registry is changed
+ - directory_results.matching_rule_found and directory_results.path_type == 'directory'
+ - file_results.matching_rule_found and file_results.path_type == 'file'
+ - registry_results.matching_rule_found and registry_results.path_type == 'registry'
+
+#####################
+### remove a rule ###
+#####################
+- name: remove directory rule
+ win_audit_rule:
+ path: "{{ test_audit_rule_folder }}"
+ user: "{{ test_audit_rule_user }}"
+ state: absent
+ register: directory
+
+- name: remove file rule
+ win_audit_rule:
+ path: "{{ test_audit_rule_file }}"
+ user: "{{ test_audit_rule_user }}"
+ state: absent
+ register: file
+
+- name: remove registry rule
+ win_audit_rule:
+ path: "{{ test_audit_rule_registry }}"
+ user: "{{ test_audit_rule_user }}"
+ state: absent
+ register: registry
+
+- name: remove get directory rule results
+ test_get_audit_rule:
+ path: "{{ test_audit_rule_folder }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_new_rights }}"
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ register: directory_results
+
+- name: remove get file rule results
+ test_get_audit_rule:
+ path: "{{ test_audit_rule_file }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_new_rights }}"
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ inheritance_flags: none
+ register: file_results
+
+- name: remove get REGISTRY rule results
+ test_get_audit_rule:
+ path: "{{ test_audit_rule_registry }}"
+ user: "{{ test_audit_rule_user }}"
+ rights: "{{ test_audit_rule_new_rights }}"
+ audit_flags: "{{ test_audit_rule_audit_flags }}"
+ register: registry_results
+
+- name: remove assert that change detected and rule is gone
+ assert:
+ that:
+ - directory is changed
+ - file is changed
+ - registry is changed
+ - not directory_results.matching_rule_found and directory_results.path_type == 'directory'
+ - not file_results.matching_rule_found and file_results.path_type == 'file'
+ - not registry_results.matching_rule_found and registry_results.path_type == 'registry'
+
+################################
+### idempotent remove a rule ###
+################################
+- name: idempotent remove directory rule
+ win_audit_rule:
+ path: "{{ test_audit_rule_folder }}"
+ user: "{{ test_audit_rule_user }}"
+ state: absent
+ register: directory
+
+- name: idempotent remove file rule
+ win_audit_rule:
+ path: "{{ test_audit_rule_file }}"
+ user: "{{ test_audit_rule_user }}"
+ state: absent
+ register: file
+
+- name: idempotent remove registry rule
+ win_audit_rule:
+ path: "{{ test_audit_rule_registry }}"
+ user: "{{ test_audit_rule_user }}"
+ state: absent
+ register: registry
+
+- name: idempotent remove assert that no change detected
+ assert:
+ that:
+ - directory is not changed and directory.path_type == 'directory'
+ - file is not changed and file.path_type == 'file'
+ - registry is not changed and registry.path_type == 'registry'
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_auto_logon/aliases b/ansible_collections/community/windows/tests/integration/targets/win_auto_logon/aliases
new file mode 100644
index 000000000..215e0b069
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_auto_logon/aliases
@@ -0,0 +1 @@
+shippable/windows/group4
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_auto_logon/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_auto_logon/defaults/main.yml
new file mode 100644
index 000000000..d5462bb6a
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_auto_logon/defaults/main.yml
@@ -0,0 +1,3 @@
+# This doesn't have to be valid, just testing weird chars in the pass
+test_logon_password: 'café - 💩'
+test_logon_password2: '.ÅÑŚÌβŁÈ [$!@^&test(;)]'
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_auto_logon/library/test_autologon_info.ps1 b/ansible_collections/community/windows/tests/integration/targets/win_auto_logon/library/test_autologon_info.ps1
new file mode 100644
index 000000000..2819151ff
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_auto_logon/library/test_autologon_info.ps1
@@ -0,0 +1,215 @@
+#!powershell
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#Requires -Module Ansible.ModuleUtils.AddType
+
+$module = [Ansible.Basic.AnsibleModule]::Create($args, @{})
+
+Add-CSharpType -AnsibleModule $module -References @'
+using Microsoft.Win32.SafeHandles;
+using System;
+using System.Runtime.ConstrainedExecution;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace Ansible.TestAutoLogonInfo
+{
+ internal class NativeHelpers
+ {
+ [StructLayout(LayoutKind.Sequential)]
+ public class LSA_OBJECT_ATTRIBUTES
+ {
+ public UInt32 Length = 0;
+ public IntPtr RootDirectory = IntPtr.Zero;
+ public IntPtr ObjectName = IntPtr.Zero;
+ public UInt32 Attributes = 0;
+ public IntPtr SecurityDescriptor = IntPtr.Zero;
+ public IntPtr SecurityQualityOfService = IntPtr.Zero;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ internal struct LSA_UNICODE_STRING
+ {
+ public UInt16 Length;
+ public UInt16 MaximumLength;
+ public IntPtr Buffer;
+
+ public static explicit operator string(LSA_UNICODE_STRING s)
+ {
+ byte[] strBytes = new byte[s.Length];
+ Marshal.Copy(s.Buffer, strBytes, 0, s.Length);
+ return Encoding.Unicode.GetString(strBytes);
+ }
+
+ public static SafeMemoryBuffer CreateSafeBuffer(string s)
+ {
+ if (s == null)
+ return new SafeMemoryBuffer(IntPtr.Zero);
+
+ byte[] stringBytes = Encoding.Unicode.GetBytes(s);
+ int structSize = Marshal.SizeOf(typeof(LSA_UNICODE_STRING));
+ IntPtr buffer = Marshal.AllocHGlobal(structSize + stringBytes.Length);
+ try
+ {
+ LSA_UNICODE_STRING lsaString = new LSA_UNICODE_STRING()
+ {
+ Length = (UInt16)(stringBytes.Length),
+ MaximumLength = (UInt16)(stringBytes.Length),
+ Buffer = IntPtr.Add(buffer, structSize),
+ };
+ Marshal.StructureToPtr(lsaString, buffer, false);
+ Marshal.Copy(stringBytes, 0, lsaString.Buffer, stringBytes.Length);
+ return new SafeMemoryBuffer(buffer);
+ }
+ catch
+ {
+ // Make sure we free the pointer before raising the exception.
+ Marshal.FreeHGlobal(buffer);
+ throw;
+ }
+ }
+ }
+ }
+
+ internal class NativeMethods
+ {
+ [DllImport("Advapi32.dll")]
+ public static extern UInt32 LsaClose(
+ IntPtr ObjectHandle);
+
+ [DllImport("Advapi32.dll")]
+ public static extern UInt32 LsaFreeMemory(
+ IntPtr Buffer);
+
+ [DllImport("Advapi32.dll")]
+ internal static extern Int32 LsaNtStatusToWinError(
+ UInt32 Status);
+
+ [DllImport("Advapi32.dll")]
+ public static extern UInt32 LsaOpenPolicy(
+ IntPtr SystemName,
+ NativeHelpers.LSA_OBJECT_ATTRIBUTES ObjectAttributes,
+ UInt32 AccessMask,
+ out SafeLsaHandle PolicyHandle);
+
+ [DllImport("Advapi32.dll")]
+ public static extern UInt32 LsaRetrievePrivateData(
+ SafeLsaHandle PolicyHandle,
+ SafeMemoryBuffer KeyName,
+ out SafeLsaMemory PrivateData);
+ }
+
+ internal class SafeLsaMemory : SafeBuffer
+ {
+ internal SafeLsaMemory() : base(true) { }
+
+ [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
+
+ protected override bool ReleaseHandle()
+ {
+ return NativeMethods.LsaFreeMemory(handle) == 0;
+ }
+ }
+
+ internal class SafeMemoryBuffer : SafeBuffer
+ {
+ internal SafeMemoryBuffer() : base(true) { }
+
+ internal SafeMemoryBuffer(IntPtr ptr) : base(true)
+ {
+ base.SetHandle(ptr);
+ }
+
+ [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
+
+ protected override bool ReleaseHandle()
+ {
+ if (handle != IntPtr.Zero)
+ Marshal.FreeHGlobal(handle);
+ return true;
+ }
+ }
+
+ public class SafeLsaHandle : SafeHandleZeroOrMinusOneIsInvalid
+ {
+ internal SafeLsaHandle() : base(true) { }
+
+ [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
+
+ protected override bool ReleaseHandle()
+ {
+ return NativeMethods.LsaClose(handle) == 0;
+ }
+ }
+
+ public class Win32Exception : System.ComponentModel.Win32Exception
+ {
+ private string _exception_msg;
+ public Win32Exception(string message) : this(Marshal.GetLastWin32Error(), message) { }
+ public Win32Exception(int errorCode, string message) : base(errorCode)
+ {
+ _exception_msg = String.Format("{0} - {1} (Win32 Error Code {2}: 0x{3})", message, base.Message, errorCode, errorCode.ToString("X8"));
+ }
+ public override string Message { get { return _exception_msg; } }
+ public static explicit operator Win32Exception(string message) { return new Win32Exception(message); }
+ }
+
+ public class LsaUtil
+ {
+ public static SafeLsaHandle OpenPolicy(UInt32 access)
+ {
+ NativeHelpers.LSA_OBJECT_ATTRIBUTES oa = new NativeHelpers.LSA_OBJECT_ATTRIBUTES();
+ SafeLsaHandle lsaHandle;
+ UInt32 res = NativeMethods.LsaOpenPolicy(IntPtr.Zero, oa, access, out lsaHandle);
+ if (res != 0)
+ throw new Win32Exception(NativeMethods.LsaNtStatusToWinError(res),
+ String.Format("LsaOpenPolicy({0}) failed", access.ToString()));
+ return lsaHandle;
+ }
+
+ public static string RetrievePrivateData(SafeLsaHandle handle, string key)
+ {
+ using (SafeMemoryBuffer keyBuffer = NativeHelpers.LSA_UNICODE_STRING.CreateSafeBuffer(key))
+ {
+ SafeLsaMemory buffer;
+ UInt32 res = NativeMethods.LsaRetrievePrivateData(handle, keyBuffer, out buffer);
+ using (buffer)
+ {
+ if (res != 0)
+ {
+ // If the data object was not found we return null to indicate it isn't set.
+ if (res == 0xC0000034) // STATUS_OBJECT_NAME_NOT_FOUND
+ return null;
+
+ throw new Win32Exception(NativeMethods.LsaNtStatusToWinError(res),
+ String.Format("LsaRetrievePrivateData({0}) failed", key));
+ }
+
+ NativeHelpers.LSA_UNICODE_STRING lsaString = (NativeHelpers.LSA_UNICODE_STRING)
+ Marshal.PtrToStructure(buffer.DangerousGetHandle(),
+ typeof(NativeHelpers.LSA_UNICODE_STRING));
+ return (string)lsaString;
+ }
+ }
+ }
+ }
+}
+'@
+
+$details = Get-ItemProperty -LiteralPath 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon'
+$module.Result.AutoAdminLogon = $details.AutoAdminLogon
+$module.Result.DefaultUserName = $details.DefaultUserName
+$module.Result.DefaultDomainName = $details.DefaultDomainName
+$module.Result.DefaultPassword = $details.DefaultPassword
+$module.Result.AutoLogonCount = $details.AutoLogonCount
+
+$handle = [Ansible.TestAutoLogonInfo.LsaUtil]::OpenPolicy(0x00000004)
+try {
+ $password = [Ansible.TestAutoLogonInfo.LsaUtil]::RetrievePrivateData($handle, 'DefaultPassword')
+ $module.Result.LsaPassword = $password
+}
+finally {
+ $handle.Dispose()
+}
+
+$module.ExitJson()
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_auto_logon/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_auto_logon/tasks/main.yml
new file mode 100644
index 000000000..d99649e3e
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_auto_logon/tasks/main.yml
@@ -0,0 +1,42 @@
+---
+- name: get user domain split for ansible_user
+ ansible.windows.win_shell: |
+ $account = New-Object -TypeName System.Security.Principal.NTAccount -ArgumentList '{{ ansible_user }}'
+ $sid = $account.Translate([System.Security.Principal.SecurityIdentifier])
+ $sid.Translate([System.Security.Principal.NTAccount]).Value -split '{{ "\\" }}'
+ changed_when: False
+ register: test_user_split
+
+- set_fact:
+ test_domain: '{{ test_user_split.stdout_lines[0] }}'
+ test_user: '{{ test_user_split.stdout_lines[1] }}'
+
+- name: ensure auto logon is cleared before test
+ win_auto_logon:
+ state: absent
+
+- name: ensure defaults are set
+ ansible.windows.win_regedit:
+ path: HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon
+ name: '{{ item.name }}'
+ data: '{{ item.value }}'
+ type: '{{ item.type }}'
+ state: present
+ loop:
+ # We set the DefaultPassword to ensure win_auto_logon clears this out
+ - name: DefaultPassword
+ value: abc
+ type: string
+ # Ensures the host we test on has a baseline key to check against
+ - name: AutoAdminLogon
+ value: 0
+ type: dword
+
+- block:
+ - name: run tests
+ include_tasks: tests.yml
+
+ always:
+ - name: make sure the auto logon is cleared
+ win_auto_logon:
+ state: absent
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_auto_logon/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_auto_logon/tasks/tests.yml
new file mode 100644
index 000000000..c25e07709
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_auto_logon/tasks/tests.yml
@@ -0,0 +1,178 @@
+# Copyright: (c) 2019, Prasoon Karunan V (@prasoonkarunan) <kvprasoon@Live.in>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: set autologon registry keys (check mode)
+ win_auto_logon:
+ username: '{{ ansible_user }}'
+ password: '{{ test_logon_password }}'
+ state: present
+ register: set_check
+ check_mode: yes
+
+- name: get acutal of set autologon registry keys (check mode)
+ test_autologon_info:
+ register: set_actual_check
+
+- name: assert set autologon registry keys (check mode)
+ assert:
+ that:
+ - set_check is changed
+ - set_actual_check.AutoAdminLogon == 0
+ - set_actual_check.AutoLogonCount == None
+ - set_actual_check.DefaultDomainName == None
+ - set_actual_check.DefaultPassword == 'abc'
+ - set_actual_check.DefaultUserName == None
+ - set_actual_check.LsaPassword == None
+
+- name: set autologon registry keys
+ win_auto_logon:
+ username: '{{ ansible_user }}'
+ password: '{{ test_logon_password }}'
+ state: present
+ register: set
+
+- name: get acutal of set autologon registry keys
+ test_autologon_info:
+ register: set_actual
+
+- name: assert set autologon registry keys
+ assert:
+ that:
+ - set is changed
+ - set_actual.AutoAdminLogon == 1
+ - set_actual.AutoLogonCount == None
+ - set_actual.DefaultDomainName == test_domain
+ - set_actual.DefaultPassword == None
+ - set_actual.DefaultUserName == test_user
+ - set_actual.LsaPassword == test_logon_password
+
+- name: set autologon registry keys (idempotent)
+ win_auto_logon:
+ username: '{{ ansible_user }}'
+ password: '{{ test_logon_password }}'
+ state: present
+ register: set_again
+
+- name: assert set autologon registry keys (idempotent)
+ assert:
+ that:
+ - not set_again is changed
+
+- name: add logon count (check mode)
+ win_auto_logon:
+ username: '{{ ansible_user }}'
+ password: '{{ test_logon_password }}'
+ logon_count: 2
+ state: present
+ register: logon_count_check
+ check_mode: yes
+
+- name: get result of add logon count (check mode)
+ test_autologon_info:
+ register: logon_count_actual_check
+
+- name: assert add logon count (check mode)
+ assert:
+ that:
+ - logon_count_check is changed
+ - logon_count_actual_check.AutoLogonCount == None
+
+- name: add logon count
+ win_auto_logon:
+ username: '{{ ansible_user }}'
+ password: '{{ test_logon_password }}'
+ logon_count: 2
+ state: present
+ register: logon_count
+
+- name: get result of add logon count
+ test_autologon_info:
+ register: logon_count_actual
+
+- name: assert add logon count
+ assert:
+ that:
+ - logon_count is changed
+ - logon_count_actual.AutoLogonCount == 2
+
+- name: change auto logon (check mode)
+ win_auto_logon:
+ username: '{{ ansible_user }}'
+ password: '{{ test_logon_password2 }}'
+ state: present
+ register: change_check
+ check_mode: yes
+
+- name: get reuslt of change auto logon (check mode)
+ test_autologon_info:
+ register: change_actual_check
+
+- name: assert change auto logon (check mode)
+ assert:
+ that:
+ - change_check is changed
+ - change_actual_check == logon_count_actual
+
+- name: change auto logon
+ win_auto_logon:
+ username: '{{ ansible_user }}'
+ password: '{{ test_logon_password2 }}'
+ state: present
+ register: change
+
+- name: get reuslt of change auto logon
+ test_autologon_info:
+ register: change_actual
+
+- name: assert change auto logon
+ assert:
+ that:
+ - change is changed
+ - change_actual.AutoLogonCount == None
+ - change_actual.LsaPassword == test_logon_password2
+
+- name: remove autologon registry keys (check mode)
+ win_auto_logon:
+ state: absent
+ register: remove_check
+ check_mode: yes
+
+- name: get result of remove autologon registry keys (check mode)
+ test_autologon_info:
+ register: remove_actual_check
+
+- name: assert remove autologon registry keys (check mode)
+ assert:
+ that:
+ - remove_check is changed
+ - remove_actual_check == change_actual
+
+- name: remove autologon registry keys
+ win_auto_logon:
+ state: absent
+ register: remove
+
+- name: get result of remove autologon registry keys
+ test_autologon_info:
+ register: remove_actual
+
+- name: assert remove autologon registry keys
+ assert:
+ that:
+ - remove is changed
+ - remove_actual.AutoAdminLogon == 0
+ - remove_actual.AutoLogonCount == None
+ - remove_actual.DefaultDomainName == None
+ - remove_actual.DefaultPassword == None
+ - remove_actual.DefaultUserName == None
+ - remove_actual.LsaPassword == None
+
+- name: remove autologon registry keys (idempotent)
+ win_auto_logon:
+ state: absent
+ register: remove_again
+
+- name: assert remove autologon registry keys (idempotent)
+ assert:
+ that:
+ - not remove_again is changed
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_certificate_info/aliases b/ansible_collections/community/windows/tests/integration/targets/win_certificate_info/aliases
new file mode 100644
index 000000000..3cf5b97e8
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_certificate_info/aliases
@@ -0,0 +1 @@
+shippable/windows/group3
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_certificate_info/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_certificate_info/defaults/main.yml
new file mode 100644
index 000000000..871dfe91d
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_certificate_info/defaults/main.yml
@@ -0,0 +1,3 @@
+win_cert_dir: '{{ remote_tmp_dir }}\win_certificate .ÅÑŚÌβŁÈ [$!@^&test(;)]'
+subj_thumbprint: 'BD7AF104CF1872BDB518D95C9534EA941665FD27'
+root_thumbprint: 'BC05633694E675449136679A658281F17A191087'
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_certificate_info/files/root-cert.pem b/ansible_collections/community/windows/tests/integration/targets/win_certificate_info/files/root-cert.pem
new file mode 100644
index 000000000..edbe6b868
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_certificate_info/files/root-cert.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDKDCCAhCgAwIBAgIJAP1vIdGgMJv/MA0GCSqGSIb3DQEBCwUAMCgxGTAXBgNV
+BAMMEHJvb3QuYW5zaWJsZS5jb20xCzAJBgNVBAYTAlVTMCAXDTE3MTIxNTA4Mzkz
+MloYDzIwODYwMTAyMDgzOTMyWjAoMRkwFwYDVQQDDBByb290LmFuc2libGUuY29t
+MQswCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMmq
+YT8eZY6rFQKnmScUGnnUH1tLQ+3WQpfKiWygCUSb1CNqO3J1u3pGMEqYM58LK4Kr
+Mpskv7K1tCV/EMZqGTqXAIfSLy9umlb/9C3AhL9thBPn5I9dam/EmrIZktI9/w5Y
+wBXn4toe+OopA3QkMQh9BUjUCPb9fdOI+ir7OGFZMmxXmiM64+BEeywM2oSGsdZ9
+5hU378UBu2IX4+OAV8Fbr2l6VW+Fxg/tKIOo6Bs46Pa4EZgtemOqs3kxYBOltBTb
+vFcLsLa4KYVu5Ge5YfB0Axfaem7PoP8IlMs8gxyojZ/r0o5hzxUcYlL/h8GeeoLW
+PFFdiAS+UgxWINOqNXMCAwEAAaNTMFEwHQYDVR0OBBYEFLp9k4LmOnAR4ROrqhb+
+CFdbk2+oMB8GA1UdIwQYMBaAFLp9k4LmOnAR4ROrqhb+CFdbk2+oMA8GA1UdEwEB
+/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAGksycHsjGbXfWfuhQh+CvXk/A2v
+MoNgiHtNMTGliVNgoVp1B1rj4x9xyZ8YrO8GAmv8jaCwCShd0B5Ul4aZVk1wglVv
+lFAwb4IAZN9jv9+fw5BRzQ2tLhkVWIEwx6pZkhGhhjBvMaplLN5JwBtsdZorFbm7
+wuKiUKcFAM28acoOhCmOhgyNNBZpZn5wXaQDY43AthJOhitAV7vph4MPUkwIJnOh
+MA5GJXEqS58TE9z9pkhQnn9598G8tmOXyA2erAoM9JAXM3EYHxVpoHBb9QRj6WAw
+XVBo6qRXkwjNEM5CbnD4hVIBsdkOGsDrgd4Q5izQZ3x+jFNkdL/zPsXjJFw=
+-----END CERTIFICATE-----
+
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_certificate_info/files/subj-cert.pem b/ansible_collections/community/windows/tests/integration/targets/win_certificate_info/files/subj-cert.pem
new file mode 100644
index 000000000..6d9ec39c7
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_certificate_info/files/subj-cert.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIC0TCCAbkCCQC/MtOBa1UDpzANBgkqhkiG9w0BAQsFADAoMRkwFwYDVQQDDBBy
+b290LmFuc2libGUuY29tMQswCQYDVQQGEwJVUzAgFw0xNzEyMTUwODU2MzBaGA8y
+MDg2MDEwMjA4NTYzMFowKzEcMBoGA1UEAwwTc3ViamVjdC5hbnNpYmxlLmNvbTEL
+MAkGA1UEBhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDszqdF
+So3GlVP1xUnN4bSPrFRFiOl/Mqup0Zn5UJJUR9wLnRD+OLcq7kKin6hYqozSu7cC
++BnWQoq7vGSSNVqv7BqFMwzGJt9IBUQv0UqIQkA/duUdKdAiMn2PQRsNDnkWEbTj
+4xsitItVNv84cDG0lkZBYyTgfyZlZLZWplkpUQkrZhoFCekZRJ+ODrqNW3W560rr
+OUIh+HiQeBqocat6OdxgICBqpUh8EVo1iha3DXjGN08q5utg6gmbIl2VBaVJjfyd
+wnUSqHylJwh6WCIEh+HXsn4ndfNWSN/fDqvi5I10V1j6Zos7yqQf8qAezUAm6eSq
+hLgZz0odq9DsO4HHAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAFK5mVIJ2D+kI0kk
+sxnW4ibWFjzlYFYPYrZg+2JFIVTbKBg1YzyhuIKm0uztqRxQq5iLn/C/uponHoqF
+7KDQI37KAJIQdgSva+mEuO9bZAXg/eegail2hN6np7HjOKlPu23s40dAbFrbcOWP
+VbsBEPDP0HLv6OgbQWzNlE9HO1b7pX6ozk3q4ULO7IR85P6OHYsBBThL+qsOTzg/
+gVknuB9+n9hgNqZcAcXBLDetOM9aEmYJCGk0enYP5UGLYpseE+rTXFbRuHTPr1o6
+e8BetiSWS/wcrV4ZF5qr9NiYt5eD6JzTB5Rn5awxxj0FwMtrBu003lLQUWxsuTzz
+35/RLY4=
+-----END CERTIFICATE-----
+
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_certificate_info/meta/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_certificate_info/meta/main.yml
new file mode 100644
index 000000000..9f37e96cd
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_certificate_info/meta/main.yml
@@ -0,0 +1,2 @@
+dependencies:
+- setup_remote_tmp_dir
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_certificate_info/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_certificate_info/tasks/main.yml
new file mode 100644
index 000000000..a91b48108
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_certificate_info/tasks/main.yml
@@ -0,0 +1,88 @@
+### keys in files/ have been generated with
+# generate root private key
+# openssl genrsa -aes256 -out enckey.pem 2048
+# openssl rsa -in envkey.pem -out root-key.pem
+#
+# generate root certificate
+# openssl req -x509 -key root-key.pem -days 24855 -out root-vert.pem -subj "/CN=root.ansible.com/C=US"
+#
+# generate subject private key
+# openssl genrsa -aes256 -out enckey.pem 2048
+# openssl rsa -in enckey.pem -out subj-key.pem
+#
+# generate subject certificate
+# openssl req -new -key subj-key.pem -out cert.csr -subj "/CN=subject.ansible.com/C=US"
+# openssl x509 -req -in cert.csr -CA root-cert.pem -CAkey root-key.pem -CAcreateserial -out subj-cert.pem -days 24855
+###
+---
+- name: ensure test dir is present
+ ansible.windows.win_file:
+ path: '{{win_cert_dir}}\exported'
+ state: directory
+
+- name: copy across test cert files
+ ansible.windows.win_copy:
+ src: files/
+ dest: '{{win_cert_dir}}'
+
+- name: subject cert imported to personal store
+ ansible.windows.win_certificate_store:
+ path: '{{win_cert_dir}}\subj-cert.pem'
+ state: present
+ store_name: My
+
+- name: root certificate imported to trusted root
+ ansible.windows.win_certificate_store:
+ path: '{{win_cert_dir}}\root-cert.pem'
+ store_name: Root
+ state: present
+
+- name: get raw root certificate
+ shell: 'cat root-cert.pem | grep "^[^-]"'
+ args:
+ chdir: '{{ role_path }}/files'
+ register: root_raw
+ delegate_to: localhost
+
+- name: get public key of root certificate
+ shell: 'openssl x509 -pubkey -noout -in root-cert.pem | grep "^[^-]"'
+ args:
+ chdir: '{{ role_path }}/files'
+ register: root_pub
+ delegate_to: localhost
+
+- name: get subject certificate
+ shell: 'cat subj-cert.pem | grep "^[^-]"'
+ args:
+ chdir: '{{ role_path }}/files'
+ register: subj_raw
+ delegate_to: localhost
+
+- name: get public key of subject certificate
+ shell: 'openssl x509 -pubkey -noout -in subj-cert.pem | grep "^[^-]"'
+ args:
+ chdir: '{{ role_path }}/files'
+ register: subj_pub
+ delegate_to: localhost
+
+- block:
+ - name: run tests
+ include_tasks: tests.yml
+
+ always:
+ - name: ensure subject cert removed from personal store
+ ansible.windows.win_certificate_store:
+ thumbprint: '{{subj_thumbprint}}'
+ state: absent
+ store_name: My
+
+ - name: ensure root cert removed from trusted root
+ ansible.windows.win_certificate_store:
+ thumbprint: '{{root_thumbprint}}'
+ state: absent
+ store_name: Root
+
+ - name: ensure test dir is deleted
+ ansible.windows.win_file:
+ path: '{{win_cert_dir}}'
+ state: absent
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_certificate_info/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_certificate_info/tasks/tests.yml
new file mode 100644
index 000000000..90eb0870b
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_certificate_info/tasks/tests.yml
@@ -0,0 +1,90 @@
+---
+
+- name: get stats on a store that doesn't exist
+ win_certificate_info:
+ store_name: teststore
+ register: test_store
+
+- name: ensure exists is false
+ assert:
+ that:
+ - test_store.exists == false
+
+- name: get stats on the root certificate store
+ win_certificate_info:
+ store_name: Root
+ register: root_store
+
+- name: at least one certificate is returned
+ assert:
+ that:
+ - "root_store.exists"
+ - "root_store.certificates | length > 0"
+
+- name: get stats on a certificate that doesn't exist
+ win_certificate_info:
+ thumbprint: ABC
+ register: actual
+
+- name: ensure exists is false
+ assert:
+ that: actual.exists == false
+
+- name: get stats on root certificate
+ win_certificate_info:
+ thumbprint: '{{ root_thumbprint }}'
+ store_name: Root
+ register: root_stats
+
+- name: root certificate stats returned are expected values
+ assert:
+ that:
+ - root_stats.exists
+ - root_stats.certificates[0].archived == false
+ - root_stats.certificates[0].dns_names == [ 'root.ansible.com' ]
+ - root_stats.certificates[0].extensions|count == 3
+ - root_stats.certificates[0].has_private_key == false
+ - root_stats.certificates[0].issued_by == 'root.ansible.com'
+ - root_stats.certificates[0].issued_to == 'root.ansible.com'
+ - root_stats.certificates[0].issuer == 'C=US, CN=root.ansible.com'
+ - root_stats.certificates[0].path_length_constraint == 0
+# - root_stats.certificates[0].public_key == (root_pub.stdout_lines|join())
+ - root_stats.certificates[0].raw == root_raw.stdout_lines|join()
+ - root_stats.certificates[0].serial_number == '00FD6F21D1A0309BFF'
+ - root_stats.certificates[0].signature_algorithm == 'sha256RSA'
+ - root_stats.certificates[0].ski == 'BA7D9382E63A7011E113ABAA16FE08575B936FA8'
+ - root_stats.certificates[0].subject == 'C=US, CN=root.ansible.com'
+ - root_stats.certificates[0].valid_from == 1513327172
+ - root_stats.certificates[0].valid_from_iso8601 == '2017-12-15T08:39:32Z'
+ - root_stats.certificates[0].valid_to == 3660799172
+ - root_stats.certificates[0].valid_to_iso8601 == '2086-01-02T08:39:32Z'
+ - root_stats.certificates[0].version == 3
+
+- name: get stats on subject certificate
+ win_certificate_info:
+ thumbprint: '{{ subj_thumbprint }}'
+ register: subj_stats
+
+- name: subject certificate stats returned are expected values
+ assert:
+ that:
+ - subj_stats.exists
+ - subj_stats.certificates[0].archived == false
+ - subj_stats.certificates[0].dns_names == [ 'subject.ansible.com' ]
+ - subj_stats.certificates[0].extensions|count == 0
+ - subj_stats.certificates[0].has_private_key == false
+ - subj_stats.certificates[0].issued_by == 'root.ansible.com'
+ - subj_stats.certificates[0].issued_to == 'subject.ansible.com'
+ - subj_stats.certificates[0].issuer == 'C=US, CN=root.ansible.com'
+ - subj_stats.certificates[0].path_length_constraint is undefined
+# - subj_stats.certificates[0].public_key == subj_pub.stdout_lines|join()
+ - subj_stats.certificates[0].raw == subj_raw.stdout_lines|join()
+ - subj_stats.certificates[0].serial_number == '00BF32D3816B5503A7'
+ - subj_stats.certificates[0].signature_algorithm == 'sha256RSA'
+ - subj_stats.certificates[0].ski is undefined
+ - subj_stats.certificates[0].subject == 'C=US, CN=subject.ansible.com'
+ - subj_stats.certificates[0].valid_from == 1513328190
+ - subj_stats.certificates[0].valid_from_iso8601 == '2017-12-15T08:56:30Z'
+ - subj_stats.certificates[0].valid_to == 3660800190
+ - subj_stats.certificates[0].valid_to_iso8601 == '2086-01-02T08:56:30Z'
+ - subj_stats.certificates[0].version == 1
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_computer_description/aliases b/ansible_collections/community/windows/tests/integration/targets/win_computer_description/aliases
new file mode 100644
index 000000000..423ce3910
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_computer_description/aliases
@@ -0,0 +1 @@
+shippable/windows/group2
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_computer_description/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_computer_description/defaults/main.yml
new file mode 100644
index 000000000..166a5248c
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_computer_description/defaults/main.yml
@@ -0,0 +1,6 @@
+test_description: This is my computer
+test_organization: iddqd
+test_owner: BFG
+test_description2: This is not my computer
+test_organization2: idkfa
+test_owner2: CACODEMON
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_computer_description/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_computer_description/tasks/main.yml
new file mode 100644
index 000000000..4c3ce3294
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_computer_description/tasks/main.yml
@@ -0,0 +1,200 @@
+---
+- name: Blank out description, organization and owner
+ win_computer_description:
+ description: ""
+ organization: ""
+ owner: ""
+ register: blank_set
+ check_mode: no
+
+- name: Change description, organization and owner in check mode
+ win_computer_description:
+ description: "{{ test_description }}"
+ organization: "{{ test_organization }}"
+ owner: "{{ test_owner }}"
+ register: change1_checkmode
+ check_mode: yes
+
+- name: Change description, organization and owner
+ win_computer_description:
+ description: "{{ test_description }}"
+ organization: "{{ test_organization }}"
+ owner: "{{ test_owner }}"
+ register: change1_set
+ check_mode: no
+
+- name: Change description, organization and owner 2nd time, there should be no change happening
+ win_computer_description:
+ description: "{{ test_description }}"
+ organization: "{{ test_organization }}"
+ owner: "{{ test_owner }}"
+ register: change1_set2
+ check_mode: no
+
+- name: Assert that the above tasks returned the expected results
+ assert:
+ that:
+ - change1_checkmode is changed
+ - change1_set is changed
+ - change1_set2 is not changed
+
+- name: Get machine description
+ ansible.windows.win_shell: (Get-CimInstance -class "Win32_OperatingSystem").description
+ register: description1_changed
+
+- name: Get organization name
+ ansible.windows.win_reg_stat:
+ path: HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion
+ name: RegisteredOrganization
+ register: organization1_changed
+
+- name: Get owner
+ ansible.windows.win_reg_stat:
+ path: HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion
+ name: RegisteredOwner
+ register: owner1_changed
+
+- name: Assert that retrieved values are equal to the values provided in the variables
+ assert:
+ that:
+ - description1_changed.stdout == "{{ test_description }}\r\n"
+ - organization1_changed.value == "{{ test_organization }}"
+ - owner1_changed.value == "{{ test_owner }}"
+
+- name: Change description and owner only in check mode
+ win_computer_description:
+ description: "{{ test_description2 }}"
+ owner: "{{ test_owner2 }}"
+ register: change2_checkmode
+ check_mode: yes
+
+- name: Change description and owner only
+ win_computer_description:
+ description: "{{ test_description2 }}"
+ owner: "{{ test_owner2 }}"
+ register: change2_set
+ check_mode: no
+
+- name: Change description and owner only 2nd time, there should be no change happening
+ win_computer_description:
+ description: "{{ test_description2 }}"
+ owner: "{{ test_owner2 }}"
+ register: change2_set2
+ check_mode: no
+
+- name: Assert that the above tasks returned the expected results
+ assert:
+ that:
+ - change2_checkmode is changed
+ - change2_set is changed
+ - change2_set2 is not changed
+
+- name: Get machine description
+ ansible.windows.win_shell: (Get-CimInstance -class "Win32_OperatingSystem").description
+ register: description2_changed
+
+- name: Get organization name
+ ansible.windows.win_reg_stat:
+ path: HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion
+ name: RegisteredOrganization
+ register: organization2_changed
+
+- name: Get owner
+ ansible.windows.win_reg_stat:
+ path: HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion
+ name: RegisteredOwner
+ register: owner2_changed
+
+- name: Assert that retrieved values are equal to the desired values
+ assert:
+ that:
+ - description2_changed.stdout == "{{ test_description2 }}\r\n"
+ - organization2_changed.value == "{{ test_organization }}"
+ - owner2_changed.value == "{{ test_owner2 }}"
+
+- name: Change organization only in check mode
+ win_computer_description:
+ organization: "{{ test_organization2 }}"
+ register: change3_checkmode
+ check_mode: yes
+
+- name: Change organization only in check mode
+ win_computer_description:
+ organization: "{{ test_organization2 }}"
+ register: change3_set
+ check_mode: no
+
+- name: Change organization only in check mode
+ win_computer_description:
+ organization: "{{ test_organization2 }}"
+ register: change3_set2
+ check_mode: no
+
+- name: Assert that the above tasks returned the expected results
+ assert:
+ that:
+ - change3_checkmode is changed
+ - change3_set is changed
+ - change3_set2 is not changed
+
+- name: Get machine description
+ ansible.windows.win_shell: (Get-CimInstance -class "Win32_OperatingSystem").description
+ register: description3_changed
+
+- name: Get organization name
+ ansible.windows.win_reg_stat:
+ path: HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion
+ name: RegisteredOrganization
+ register: organization3_changed
+
+- name: Get owner
+ ansible.windows.win_reg_stat:
+ path: HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion
+ name: RegisteredOwner
+ register: owner3_changed
+
+- name: Assert that retrieved values are equal to the desired values
+ assert:
+ that:
+ - description3_changed.stdout == "{{ test_description2 }}\r\n"
+ - organization3_changed.value == "{{ test_organization2 }}"
+ - owner3_changed.value == "{{ test_owner2 }}"
+
+- name: Try to apply the same values again in check mode, there should be no change
+ win_computer_description:
+ description: "{{ test_description2 }}"
+ organization: "{{ test_organization2 }}"
+ owner: "{{ test_owner2 }}"
+ register: change4_checkmode
+ check_mode: yes
+
+- name: Try to apply the same values again, there should be no change
+ win_computer_description:
+ description: "{{ test_description2 }}"
+ organization: "{{ test_organization2 }}"
+ owner: "{{ test_owner2 }}"
+ register: change4_set
+ check_mode: no
+
+- name: Try to apply the same values again for 2nd time, there should be no change
+ win_computer_description:
+ description: "{{ test_description2 }}"
+ organization: "{{ test_organization2 }}"
+ owner: "{{ test_owner2 }}"
+ register: change4_set2
+ check_mode: no
+
+- name: Assert that the above tasks returned the expected results
+ assert:
+ that:
+ - change4_checkmode is not changed
+ - change4_set is not changed
+ - change4_set2 is not changed
+
+- name: Blank the test values
+ win_computer_description:
+ description: ''
+ organization: ''
+ owner: ''
+ register: blank2_set
+ check_mode: no
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_credential/aliases b/ansible_collections/community/windows/tests/integration/targets/win_credential/aliases
new file mode 100644
index 000000000..423ce3910
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_credential/aliases
@@ -0,0 +1 @@
+shippable/windows/group2
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_credential/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_credential/defaults/main.yml
new file mode 100644
index 000000000..c330762d4
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_credential/defaults/main.yml
@@ -0,0 +1,19 @@
+# The certificate in files/cert.pfx was generated with the following commands
+#
+# cat > client.cnf <<EOL
+# [ssl_client]
+# basicConstraints = CA:FALSE
+# nsCertType = client
+# keyUsage = digitalSignature, keyEncipherment
+# extendedKeyUsage = clientAuth
+# EOL
+#
+# openssl genrsa -aes256 -passout pass:password1 -out cert.key 2048
+# openssl req -new -subj '/CN=ansible.domain.com' -key cert.key -out cert.req -passin pass:password1
+# openssl x509 -sha256 -req -in cert.req -days 24855 -signkey cert.key -out cert.crt -extensions ssl_client -extfile client.cnf -passin pass:password1
+# openssl pkcs12 -export -in cert.crt -inkey cert.key -out cert.pfx -passin pass:password1 -passout pass:password1
+---
+test_credential_dir: '{{ remote_tmp_dir }}\win_credential_manager'
+test_hostname: ansible.domain.com
+key_password: password1
+cert_thumbprint: 56841AAFDD19D7DF474BDA24D01D88BD8025A00A
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_credential/files/cert.pfx b/ansible_collections/community/windows/tests/integration/targets/win_credential/files/cert.pfx
new file mode 100644
index 000000000..9cffb6696
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_credential/files/cert.pfx
Binary files differ
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_credential/library/test_cred_facts.ps1 b/ansible_collections/community/windows/tests/integration/targets/win_credential/library/test_cred_facts.ps1
new file mode 100644
index 000000000..59206638f
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_credential/library/test_cred_facts.ps1
@@ -0,0 +1,501 @@
+#!powershell
+
+# Copyright: (c) 2018, Ansible Project
+# 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.AddType
+
+$spec = @{
+ options = @{
+ name = @{ type = "str"; required = $true }
+ type = @{ type = "str"; required = $true; choices = @("domain_password", "domain_certificate", "generic_password", "generic_certificate") }
+ }
+ supports_check_mode = $true
+}
+
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
+
+$name = $module.Params.name
+$type = $module.Params.type
+
+Add-CSharpType -AnsibleModule $module -References @'
+using Microsoft.Win32.SafeHandles;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.ConstrainedExecution;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace Ansible.CredentialManager
+{
+ internal class NativeHelpers
+ {
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ public class CREDENTIAL
+ {
+ public CredentialFlags Flags;
+ public CredentialType Type;
+ [MarshalAs(UnmanagedType.LPWStr)] public string TargetName;
+ [MarshalAs(UnmanagedType.LPWStr)] public string Comment;
+ public FILETIME LastWritten;
+ public UInt32 CredentialBlobSize;
+ public IntPtr CredentialBlob;
+ public CredentialPersist Persist;
+ public UInt32 AttributeCount;
+ public IntPtr Attributes;
+ [MarshalAs(UnmanagedType.LPWStr)] public string TargetAlias;
+ [MarshalAs(UnmanagedType.LPWStr)] public string UserName;
+
+ public static explicit operator Credential(CREDENTIAL v)
+ {
+ byte[] secret = new byte[(int)v.CredentialBlobSize];
+ if (v.CredentialBlob != IntPtr.Zero)
+ Marshal.Copy(v.CredentialBlob, secret, 0, secret.Length);
+
+ List<CredentialAttribute> attributes = new List<CredentialAttribute>();
+ if (v.AttributeCount > 0)
+ {
+ CREDENTIAL_ATTRIBUTE[] rawAttributes = new CREDENTIAL_ATTRIBUTE[v.AttributeCount];
+ Credential.PtrToStructureArray(rawAttributes, v.Attributes);
+ attributes = rawAttributes.Select(x => (CredentialAttribute)x).ToList();
+ }
+
+ string userName = v.UserName;
+ if (v.Type == CredentialType.DomainCertificate || v.Type == CredentialType.GenericCertificate)
+ userName = Credential.UnmarshalCertificateCredential(userName);
+
+ return new Credential
+ {
+ Type = v.Type,
+ TargetName = v.TargetName,
+ Comment = v.Comment,
+ LastWritten = (DateTimeOffset)v.LastWritten,
+ Secret = secret,
+ Persist = v.Persist,
+ Attributes = attributes,
+ TargetAlias = v.TargetAlias,
+ UserName = userName,
+ Loaded = true,
+ };
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CREDENTIAL_ATTRIBUTE
+ {
+ [MarshalAs(UnmanagedType.LPWStr)] public string Keyword;
+ public UInt32 Flags; // Set to 0 and is reserved
+ public UInt32 ValueSize;
+ public IntPtr Value;
+
+ public static explicit operator CredentialAttribute(CREDENTIAL_ATTRIBUTE v)
+ {
+ byte[] value = new byte[v.ValueSize];
+ Marshal.Copy(v.Value, value, 0, (int)v.ValueSize);
+
+ return new CredentialAttribute
+ {
+ Keyword = v.Keyword,
+ Flags = v.Flags,
+ Value = value,
+ };
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct FILETIME
+ {
+ internal UInt32 dwLowDateTime;
+ internal UInt32 dwHighDateTime;
+
+ public static implicit operator long(FILETIME v) { return ((long)v.dwHighDateTime << 32) + v.dwLowDateTime; }
+ public static explicit operator DateTimeOffset(FILETIME v) { return DateTimeOffset.FromFileTime(v); }
+ public static explicit operator FILETIME(DateTimeOffset v)
+ {
+ return new FILETIME()
+ {
+ dwLowDateTime = (UInt32)v.ToFileTime(),
+ dwHighDateTime = ((UInt32)v.ToFileTime() >> 32),
+ };
+ }
+ }
+
+ [Flags]
+ public enum CredentialCreateFlags : uint
+ {
+ PreserveCredentialBlob = 1,
+ }
+
+ [Flags]
+ public enum CredentialFlags
+ {
+ None = 0,
+ PromptNow = 2,
+ UsernameTarget = 4,
+ }
+
+ public enum CredMarshalType : uint
+ {
+ CertCredential = 1,
+ UsernameTargetCredential,
+ BinaryBlobCredential,
+ UsernameForPackedCredential,
+ BinaryBlobForSystem,
+ }
+ }
+
+ internal class NativeMethods
+ {
+ [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern bool CredDeleteW(
+ [MarshalAs(UnmanagedType.LPWStr)] string TargetName,
+ CredentialType Type,
+ UInt32 Flags);
+
+ [DllImport("advapi32.dll")]
+ public static extern void CredFree(
+ IntPtr Buffer);
+
+ [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern bool CredMarshalCredentialW(
+ NativeHelpers.CredMarshalType CredType,
+ SafeMemoryBuffer Credential,
+ out SafeCredentialBuffer MarshaledCredential);
+
+ [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern bool CredReadW(
+ [MarshalAs(UnmanagedType.LPWStr)] string TargetName,
+ CredentialType Type,
+ UInt32 Flags,
+ out SafeCredentialBuffer Credential);
+
+ [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern bool CredUnmarshalCredentialW(
+ [MarshalAs(UnmanagedType.LPWStr)] string MarshaledCredential,
+ out NativeHelpers.CredMarshalType CredType,
+ out SafeCredentialBuffer Credential);
+
+ [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern bool CredWriteW(
+ NativeHelpers.CREDENTIAL Credential,
+ NativeHelpers.CredentialCreateFlags Flags);
+ }
+
+ internal class SafeCredentialBuffer : SafeHandleZeroOrMinusOneIsInvalid
+ {
+ public SafeCredentialBuffer() : base(true) { }
+
+ [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
+ protected override bool ReleaseHandle()
+ {
+ NativeMethods.CredFree(handle);
+ return true;
+ }
+ }
+
+ internal class SafeMemoryBuffer : SafeHandleZeroOrMinusOneIsInvalid
+ {
+ public SafeMemoryBuffer() : base(true) { }
+ public SafeMemoryBuffer(int cb) : base(true)
+ {
+ base.SetHandle(Marshal.AllocHGlobal(cb));
+ }
+ public SafeMemoryBuffer(IntPtr handle) : base(true)
+ {
+ base.SetHandle(handle);
+ }
+ [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
+ protected override bool ReleaseHandle()
+ {
+ Marshal.FreeHGlobal(handle);
+ return true;
+ }
+ }
+
+ public class Win32Exception : System.ComponentModel.Win32Exception
+ {
+ private string _exception_msg;
+ public Win32Exception(string message) : this(Marshal.GetLastWin32Error(), message) { }
+ public Win32Exception(int errorCode, string message) : base(errorCode)
+ {
+ _exception_msg = String.Format("{0} - {1} (Win32 Error Code {2}: 0x{3})", message, base.Message, errorCode, errorCode.ToString("X8"));
+ }
+ public override string Message { get { return _exception_msg; } }
+ public static explicit operator Win32Exception(string message) { return new Win32Exception(message); }
+ }
+
+ public enum CredentialPersist
+ {
+ Session = 1,
+ LocalMachine = 2,
+ Enterprise = 3,
+ }
+
+ public enum CredentialType
+ {
+ Generic = 1,
+ DomainPassword = 2,
+ DomainCertificate = 3,
+ DomainVisiblePassword = 4,
+ GenericCertificate = 5,
+ DomainExtended = 6,
+ Maximum = 7,
+ MaximumEx = 1007,
+ }
+
+ public class CredentialAttribute
+ {
+ public string Keyword;
+ public UInt32 Flags;
+ public byte[] Value;
+ }
+
+ public class Credential
+ {
+ public CredentialType Type;
+ public string TargetName;
+ public string Comment;
+ public DateTimeOffset LastWritten;
+ public byte[] Secret;
+ public CredentialPersist Persist;
+ public List<CredentialAttribute> Attributes = new List<CredentialAttribute>();
+ public string TargetAlias;
+ public string UserName;
+
+ // Used to track whether the credential has been loaded into the store or not
+ public bool Loaded { get; internal set; }
+
+ public void Delete()
+ {
+ if (!Loaded)
+ return;
+
+ if (!NativeMethods.CredDeleteW(TargetName, Type, 0))
+ throw new Win32Exception(String.Format("CredDeleteW({0}) failed", TargetName));
+ Loaded = false;
+ }
+
+ public void Write(bool preserveExisting)
+ {
+ string userName = UserName;
+ // Convert the certificate thumbprint to the string expected
+ if (Type == CredentialType.DomainCertificate || Type == CredentialType.GenericCertificate)
+ userName = Credential.MarshalCertificateCredential(userName);
+
+ NativeHelpers.CREDENTIAL credential = new NativeHelpers.CREDENTIAL
+ {
+ Flags = NativeHelpers.CredentialFlags.None,
+ Type = Type,
+ TargetName = TargetName,
+ Comment = Comment,
+ LastWritten = new NativeHelpers.FILETIME(),
+ CredentialBlobSize = (UInt32)(Secret == null ? 0 : Secret.Length),
+ CredentialBlob = IntPtr.Zero, // Must be allocated and freed outside of this to ensure no memory leaks
+ Persist = Persist,
+ AttributeCount = (UInt32)(Attributes.Count),
+ Attributes = IntPtr.Zero, // Attributes must be allocated and freed outside of this to ensure no memory leaks
+ TargetAlias = TargetAlias,
+ UserName = userName,
+ };
+
+ using (SafeMemoryBuffer credentialBlob = new SafeMemoryBuffer((int)credential.CredentialBlobSize))
+ {
+ if (Secret != null)
+ Marshal.Copy(Secret, 0, credentialBlob.DangerousGetHandle(), Secret.Length);
+ credential.CredentialBlob = credentialBlob.DangerousGetHandle();
+
+ // Store the CREDENTIAL_ATTRIBUTE value in a safe memory buffer and make sure we dispose in all cases
+ List<SafeMemoryBuffer> attributeBuffers = new List<SafeMemoryBuffer>();
+ try
+ {
+ int attributeLength = Attributes.Sum(a => Marshal.SizeOf(typeof(NativeHelpers.CREDENTIAL_ATTRIBUTE)));
+ byte[] attributeBytes = new byte[attributeLength];
+ int offset = 0;
+ foreach (CredentialAttribute attribute in Attributes)
+ {
+ SafeMemoryBuffer attributeBuffer = new SafeMemoryBuffer(attribute.Value.Length);
+ attributeBuffers.Add(attributeBuffer);
+ if (attribute.Value != null)
+ Marshal.Copy(attribute.Value, 0, attributeBuffer.DangerousGetHandle(), attribute.Value.Length);
+
+ NativeHelpers.CREDENTIAL_ATTRIBUTE credentialAttribute = new NativeHelpers.CREDENTIAL_ATTRIBUTE
+ {
+ Keyword = attribute.Keyword,
+ Flags = attribute.Flags,
+ ValueSize = (UInt32)(attribute.Value == null ? 0 : attribute.Value.Length),
+ Value = attributeBuffer.DangerousGetHandle(),
+ };
+ int attributeStructLength = Marshal.SizeOf(typeof(NativeHelpers.CREDENTIAL_ATTRIBUTE));
+
+ byte[] attrBytes = new byte[attributeStructLength];
+ using (SafeMemoryBuffer tempBuffer = new SafeMemoryBuffer(attributeStructLength))
+ {
+ Marshal.StructureToPtr(credentialAttribute, tempBuffer.DangerousGetHandle(), false);
+ Marshal.Copy(tempBuffer.DangerousGetHandle(), attrBytes, 0, attributeStructLength);
+ }
+ Buffer.BlockCopy(attrBytes, 0, attributeBytes, offset, attributeStructLength);
+ offset += attributeStructLength;
+ }
+
+ using (SafeMemoryBuffer attributes = new SafeMemoryBuffer(attributeBytes.Length))
+ {
+ if (attributeBytes.Length != 0)
+ Marshal.Copy(attributeBytes, 0, attributes.DangerousGetHandle(), attributeBytes.Length);
+ credential.Attributes = attributes.DangerousGetHandle();
+
+ NativeHelpers.CredentialCreateFlags createFlags = 0;
+ if (preserveExisting)
+ createFlags |= NativeHelpers.CredentialCreateFlags.PreserveCredentialBlob;
+
+ if (!NativeMethods.CredWriteW(credential, createFlags))
+ throw new Win32Exception(String.Format("CredWriteW({0}) failed", TargetName));
+ }
+ }
+ finally
+ {
+ foreach (SafeMemoryBuffer attributeBuffer in attributeBuffers)
+ attributeBuffer.Dispose();
+ }
+ }
+ Loaded = true;
+ }
+
+ public static Credential GetCredential(string target, CredentialType type)
+ {
+ SafeCredentialBuffer buffer;
+ if (!NativeMethods.CredReadW(target, type, 0, out buffer))
+ {
+ int lastErr = Marshal.GetLastWin32Error();
+
+ // Not running with CredSSP or Become so cannot manage the user's credentials
+ if (lastErr == 0x00000520) // ERROR_NO_SUCH_LOGON_SESSION
+ throw new InvalidOperationException("Failed to access the user's credential store, run the module with become or CredSSP");
+ else if (lastErr == 0x00000490) // ERROR_NOT_FOUND
+ return null;
+ throw new Win32Exception(lastErr, "CredEnumerateW() failed");
+ }
+
+ using (buffer)
+ {
+ NativeHelpers.CREDENTIAL credential = (NativeHelpers.CREDENTIAL)Marshal.PtrToStructure(
+ buffer.DangerousGetHandle(), typeof(NativeHelpers.CREDENTIAL));
+ return (Credential)credential;
+ }
+ }
+
+ public static string MarshalCertificateCredential(string thumbprint)
+ {
+ // CredWriteW requires the UserName field to be the value of CredMarshalCredentialW() when writting a
+ // certificate auth. This converts the UserName property to the format required.
+
+ // While CERT_CREDENTIAL_INFO is the correct structure, we manually marshal the data in order to
+ // support different cert hash lengths in the future.
+ // https://docs.microsoft.com/en-us/windows/desktop/api/wincred/ns-wincred-_cert_credential_info
+ int hexLength = thumbprint.Length;
+ byte[] credInfo = new byte[sizeof(UInt32) + (hexLength / 2)];
+
+ // First field is cbSize which is a UInt32 value denoting the size of the total structure
+ Array.Copy(BitConverter.GetBytes((UInt32)credInfo.Length), credInfo, sizeof(UInt32));
+
+ // Now copy the byte representation of the thumbprint to the rest of the struct bytes
+ for (int i = 0; i < hexLength; i += 2)
+ credInfo[sizeof(UInt32) + (i / 2)] = Convert.ToByte(thumbprint.Substring(i, 2), 16);
+
+ IntPtr pCredInfo = Marshal.AllocHGlobal(credInfo.Length);
+ Marshal.Copy(credInfo, 0, pCredInfo, credInfo.Length);
+ SafeMemoryBuffer pCredential = new SafeMemoryBuffer(pCredInfo);
+
+ NativeHelpers.CredMarshalType marshalType = NativeHelpers.CredMarshalType.CertCredential;
+ using (pCredential)
+ {
+ SafeCredentialBuffer marshaledCredential;
+ if (!NativeMethods.CredMarshalCredentialW(marshalType, pCredential, out marshaledCredential))
+ throw new Win32Exception("CredMarshalCredentialW() failed");
+ using (marshaledCredential)
+ return Marshal.PtrToStringUni(marshaledCredential.DangerousGetHandle());
+ }
+ }
+
+ public static string UnmarshalCertificateCredential(string value)
+ {
+ NativeHelpers.CredMarshalType credType;
+ SafeCredentialBuffer pCredInfo;
+ if (!NativeMethods.CredUnmarshalCredentialW(value, out credType, out pCredInfo))
+ throw new Win32Exception("CredUnmarshalCredentialW() failed");
+
+ using (pCredInfo)
+ {
+ if (credType != NativeHelpers.CredMarshalType.CertCredential)
+ throw new InvalidOperationException(String.Format("Expected unmarshalled cred type of CertCredential, received {0}", credType));
+
+ byte[] structSizeBytes = new byte[sizeof(UInt32)];
+ Marshal.Copy(pCredInfo.DangerousGetHandle(), structSizeBytes, 0, sizeof(UInt32));
+ UInt32 structSize = BitConverter.ToUInt32(structSizeBytes, 0);
+
+ byte[] certInfoBytes = new byte[structSize];
+ Marshal.Copy(pCredInfo.DangerousGetHandle(), certInfoBytes, 0, certInfoBytes.Length);
+
+ StringBuilder hex = new StringBuilder((certInfoBytes.Length - sizeof(UInt32)) * 2);
+ for (int i = 4; i < certInfoBytes.Length; i++)
+ hex.AppendFormat("{0:x2}", certInfoBytes[i]);
+
+ return hex.ToString().ToUpperInvariant();
+ }
+ }
+
+ internal static void PtrToStructureArray<T>(T[] array, IntPtr ptr)
+ {
+ IntPtr ptrOffset = ptr;
+ for (int i = 0; i < array.Length; i++, ptrOffset = IntPtr.Add(ptrOffset, Marshal.SizeOf(typeof(T))))
+ array[i] = (T)Marshal.PtrToStructure(ptrOffset, typeof(T));
+ }
+ }
+}
+'@
+
+$type = switch ($type) {
+ "domain_password" { [Ansible.CredentialManager.CredentialType]::DomainPassword }
+ "domain_certificate" { [Ansible.CredentialManager.CredentialType]::DomainCertificate }
+ "generic_password" { [Ansible.CredentialManager.CredentialType]::Generic }
+ "generic_certificate" { [Ansible.CredentialManager.CredentialType]::GenericCertificate }
+}
+
+$credential = [Ansible.CredentialManager.Credential]::GetCredential($name, $type)
+if ($null -ne $credential) {
+ $module.Result.exists = $true
+ $module.Result.alias = $credential.TargetAlias
+ $module.Result.attributes = [System.Collections.ArrayList]@()
+ $module.Result.comment = $credential.Comment
+ $module.Result.name = $credential.TargetName
+ $module.Result.persistence = $credential.Persist.ToString()
+ $module.Result.type = $credential.Type.ToString()
+ $module.Result.username = $credential.UserName
+
+ if ($null -ne $credential.Secret) {
+ $module.Result.secret = [System.Convert]::ToBase64String($credential.Secret)
+ }
+ else {
+ $module.Result.secret = $null
+ }
+
+ foreach ($attribute in $credential.Attributes) {
+ $attribute_info = @{
+ name = $attribute.Keyword
+ }
+ if ($null -ne $attribute.Value) {
+ $attribute_info.data = [System.Convert]::ToBase64String($attribute.Value)
+ }
+ else {
+ $attribute_info.data = $null
+ }
+ $module.Result.attributes.Add($attribute_info) > $null
+ }
+}
+else {
+ $module.Result.exists = $false
+}
+
+$module.ExitJson()
+
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_credential/meta/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_credential/meta/main.yml
new file mode 100644
index 000000000..9f37e96cd
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_credential/meta/main.yml
@@ -0,0 +1,2 @@
+dependencies:
+- setup_remote_tmp_dir
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_credential/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_credential/tasks/main.yml
new file mode 100644
index 000000000..1ec3bbb3a
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_credential/tasks/main.yml
@@ -0,0 +1,64 @@
+---
+- name: ensure test dir is present
+ ansible.windows.win_file:
+ path: '{{ test_credential_dir }}'
+ state: directory
+
+- name: copy the pfx certificate
+ ansible.windows.win_copy:
+ src: cert.pfx
+ dest: '{{ test_credential_dir }}\cert.pfx'
+
+- name: import the pfx into the personal store
+ ansible.windows.win_certificate_store:
+ path: '{{ test_credential_dir }}\cert.pfx'
+ state: present
+ store_location: CurrentUser
+ store_name: My
+ password: '{{ key_password }}'
+ vars: &become_vars
+ ansible_become: True
+ ansible_become_method: runas
+ ansible_become_user: '{{ ansible_user }}'
+ ansible_become_pass: '{{ ansible_password }}'
+
+- name: ensure test credentials are removed before testing
+ win_credential:
+ name: '{{ test_hostname }}'
+ type: '{{ item }}'
+ state: absent
+ vars: *become_vars
+ with_items:
+ - domain_password
+ - domain_certificate
+ - generic_password
+ - generic_certificate
+
+- block:
+ - name: run tests
+ include_tasks: tests.yml
+
+ always:
+ - name: remove the pfx from the personal store
+ ansible.windows.win_certificate_store:
+ state: absent
+ thumbprint: '{{ cert_thumbprint }}'
+ store_location: CurrentUser
+ store_name: My
+
+ - name: remove test credentials
+ win_credential:
+ name: '{{ test_hostname }}'
+ type: '{{ item }}'
+ state: absent
+ vars: *become_vars
+ with_items:
+ - domain_password
+ - domain_certificate
+ - generic_password
+ - generic_certificate
+
+ - name: remove test dir
+ ansible.windows.win_file:
+ path: '{{ test_credential_dir }}'
+ state: absent
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_credential/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_credential/tasks/tests.yml
new file mode 100644
index 000000000..cec2cf023
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_credential/tasks/tests.yml
@@ -0,0 +1,638 @@
+---
+- name: fail to run the module without become
+ win_credential:
+ name: '{{ test_hostname }}'
+ type: domain_password
+ username: DOMAIN\username
+ secret: password
+ state: present
+ register: fail_no_become
+ failed_when: '"Failed to access the user''s credential store, run the module with become" not in fail_no_become.msg'
+
+- name: create domain user credential (check mode)
+ win_credential:
+ name: '{{ test_hostname }}'
+ type: domain_password
+ username: DOMAIN\username
+ secret: password
+ state: present
+ register: domain_user_check
+ check_mode: True
+ vars: &become_vars
+ ansible_become: True
+ ansible_become_method: runas
+ ansible_become_user: '{{ ansible_user }}'
+ ansible_become_pass: '{{ ansible_password }}'
+
+- name: get result of create domain user credential (check mode)
+ test_cred_facts:
+ name: '{{ test_hostname }}'
+ type: domain_password
+ register: domain_user_actual_check
+ vars: *become_vars
+
+- name: asset create domain user credential (check mode)
+ assert:
+ that:
+ - domain_user_check is changed
+ - not domain_user_actual_check.exists
+
+- name: create domain user credential
+ win_credential:
+ name: '{{ test_hostname }}'
+ type: domain_password
+ username: DOMAIN\username
+ secret: password
+ state: present
+ register: domain_user
+ vars: *become_vars
+
+- name: get result of create domain user credential
+ test_cred_facts:
+ name: '{{ test_hostname }}'
+ type: domain_password
+ register: domain_user_actual
+ vars: *become_vars
+
+- name: asset create domain user credential
+ assert:
+ that:
+ - domain_user is changed
+ - domain_user_actual.exists
+ - domain_user_actual.alias == None
+ - domain_user_actual.attributes == []
+ - domain_user_actual.comment == None
+ - domain_user_actual.name == test_hostname
+ - domain_user_actual.persistence == "LocalMachine"
+ - domain_user_actual.secret == ""
+ - domain_user_actual.type == "DomainPassword"
+ - domain_user_actual.username == "DOMAIN\\username"
+
+- name: create domain user credential again always update
+ win_credential:
+ name: '{{ test_hostname }}'
+ type: domain_password
+ username: DOMAIN\username
+ secret: password
+ state: present
+ register: domain_user_again_always
+ vars: *become_vars
+
+- name: create domain user credential again on_create
+ win_credential:
+ name: '{{ test_hostname }}'
+ type: domain_password
+ username: DOMAIN\username
+ secret: password
+ update_secret: on_create
+ state: present
+ register: domain_user_again_on_create
+ vars: *become_vars
+
+- name: assert create domain user credential again
+ assert:
+ that:
+ - domain_user_again_always is changed
+ - not domain_user_again_on_create is changed
+
+- name: update credential (check mode)
+ win_credential:
+ name: '{{ test_hostname }}'
+ type: domain_password
+ username: DOMAIN\username2
+ alias: ansible
+ attributes:
+ - name: attribute 1
+ data: attribute 1 value
+ - name: attribute 2
+ data: '{{ "attribute 2 value" | b64encode }}'
+ data_format: base64
+ comment: Credential comment
+ persistence: enterprise
+ state: present
+ register: update_cred_check
+ check_mode: True
+ vars: *become_vars
+
+- name: get result of update credential (check mode)
+ test_cred_facts:
+ name: '{{ test_hostname }}'
+ type: domain_password
+ register: update_cred_actual_check
+ vars: *become_vars
+
+- name: assert update credential (check mode)
+ assert:
+ that:
+ - update_cred_check is changed
+ - update_cred_actual_check.exists
+ - update_cred_actual_check.alias == None
+ - update_cred_actual_check.attributes == []
+ - update_cred_actual_check.comment == None
+ - update_cred_actual_check.name == test_hostname
+ - update_cred_actual_check.persistence == "LocalMachine"
+ - update_cred_actual_check.secret == ""
+ - update_cred_actual_check.type == "DomainPassword"
+ - update_cred_actual_check.username == "DOMAIN\\username"
+
+- name: update credential
+ win_credential:
+ name: '{{ test_hostname }}'
+ type: domain_password
+ username: DOMAIN\username2
+ alias: ansible
+ attributes:
+ - name: attribute 1
+ data: attribute 1 value
+ - name: attribute 2
+ data: '{{ "attribute 2 value" | b64encode }}'
+ data_format: base64
+ comment: Credential comment
+ persistence: enterprise
+ state: present
+ register: update_cred
+ vars: *become_vars
+
+- name: get result of update credential
+ test_cred_facts:
+ name: '{{ test_hostname }}'
+ type: domain_password
+ register: update_cred_actual
+ vars: *become_vars
+
+- name: assert update credential
+ assert:
+ that:
+ - update_cred is changed
+ - update_cred_actual.exists
+ - update_cred_actual.alias == "ansible"
+ - update_cred_actual.attributes|count == 2
+ - update_cred_actual.attributes[0].name == "attribute 1"
+ - update_cred_actual.attributes[0].data == "attribute 1 value"|b64encode
+ - update_cred_actual.attributes[1].name == "attribute 2"
+ - update_cred_actual.attributes[1].data == "attribute 2 value"|b64encode
+ - update_cred_actual.comment == "Credential comment"
+ - update_cred_actual.name == test_hostname
+ - update_cred_actual.persistence == "Enterprise"
+ - update_cred_actual.secret == ""
+ - update_cred_actual.type == "DomainPassword"
+ - update_cred_actual.username == "DOMAIN\\username2"
+
+- name: update credential again
+ win_credential:
+ name: '{{ test_hostname }}'
+ type: domain_password
+ username: DOMAIN\username2
+ alias: ansible
+ attributes:
+ - name: attribute 1
+ data: attribute 1 value
+ - name: attribute 2
+ data: '{{ "attribute 2 value" | b64encode }}'
+ data_format: base64
+ comment: Credential comment
+ persistence: enterprise
+ state: present
+ register: update_cred_again
+ vars: *become_vars
+
+- name: assert update credential again
+ assert:
+ that:
+ - not update_cred_again is changed
+
+- name: add new attribute
+ win_credential:
+ name: '{{ test_hostname }}'
+ type: domain_password
+ username: DOMAIN\username2
+ alias: ansible
+ attributes:
+ - name: attribute 1
+ data: attribute 1 value
+ - name: attribute 2
+ data: '{{ "attribute 2 value" | b64encode }}'
+ data_format: base64
+ - name: attribute 3
+ data: attribute 3 value
+ comment: Credential comment
+ persistence: enterprise
+ state: present
+ register: add_attribute
+ vars: *become_vars
+
+- name: get result of add new attribute
+ test_cred_facts:
+ name: '{{ test_hostname }}'
+ type: domain_password
+ register: add_attribute_actual
+ vars: *become_vars
+
+- name: assert add new attribute
+ assert:
+ that:
+ - add_attribute is changed
+ - add_attribute_actual.attributes|count == 3
+ - add_attribute_actual.attributes[0].name == "attribute 1"
+ - add_attribute_actual.attributes[0].data == "attribute 1 value"|b64encode
+ - add_attribute_actual.attributes[1].name == "attribute 2"
+ - add_attribute_actual.attributes[1].data == "attribute 2 value"|b64encode
+ - add_attribute_actual.attributes[2].name == "attribute 3"
+ - add_attribute_actual.attributes[2].data == "attribute 3 value"|b64encode
+
+- name: remove attribute
+ win_credential:
+ name: '{{ test_hostname }}'
+ type: domain_password
+ username: DOMAIN\username2
+ alias: ansible
+ attributes:
+ - name: attribute 1
+ data: attribute 1 value
+ - name: attribute 2
+ data: '{{ "attribute 2 value" | b64encode }}'
+ data_format: base64
+ comment: Credential comment
+ persistence: enterprise
+ state: present
+ register: remove_attribute
+ vars: *become_vars
+
+- name: get result of remove attribute
+ test_cred_facts:
+ name: '{{ test_hostname }}'
+ type: domain_password
+ register: remove_attribute_actual
+ vars: *become_vars
+
+- name: assert remove attribute
+ assert:
+ that:
+ - remove_attribute is changed
+ - remove_attribute_actual.attributes|count == 2
+ - remove_attribute_actual.attributes[0].name == "attribute 1"
+ - remove_attribute_actual.attributes[0].data == "attribute 1 value"|b64encode
+ - remove_attribute_actual.attributes[1].name == "attribute 2"
+ - remove_attribute_actual.attributes[1].data == "attribute 2 value"|b64encode
+
+- name: edit attribute
+ win_credential:
+ name: '{{ test_hostname }}'
+ type: domain_password
+ username: DOMAIN\username2
+ alias: ansible
+ attributes:
+ - name: attribute 1
+ data: attribute 1 value new
+ - name: attribute 2
+ data: '{{ "attribute 2 value" | b64encode }}'
+ data_format: base64
+ comment: Credential comment
+ persistence: enterprise
+ state: present
+ register: edit_attribute
+ vars: *become_vars
+
+- name: get result of edit attribute
+ test_cred_facts:
+ name: '{{ test_hostname }}'
+ type: domain_password
+ register: edit_attribute_actual
+ vars: *become_vars
+
+- name: assert remove attribute
+ assert:
+ that:
+ - edit_attribute is changed
+ - edit_attribute_actual.attributes|count == 2
+ - edit_attribute_actual.attributes[0].name == "attribute 1"
+ - edit_attribute_actual.attributes[0].data == "attribute 1 value new"|b64encode
+ - edit_attribute_actual.attributes[1].name == "attribute 2"
+ - edit_attribute_actual.attributes[1].data == "attribute 2 value"|b64encode
+
+- name: remove credential (check mode)
+ win_credential:
+ name: '{{ test_hostname }}'
+ type: domain_password
+ state: absent
+ register: remove_cred_check
+ check_mode: True
+ vars: *become_vars
+
+- name: get result of remove credential (check mode)
+ test_cred_facts:
+ name: '{{ test_hostname }}'
+ type: domain_password
+ register: remove_cred_actual_check
+ vars: *become_vars
+
+- name: assert remove credential (check mode)
+ assert:
+ that:
+ - remove_cred_check is changed
+ - remove_cred_actual_check.exists
+
+- name: remove credential
+ win_credential:
+ name: '{{ test_hostname }}'
+ type: domain_password
+ state: absent
+ register: remove_cred
+ vars: *become_vars
+
+- name: get result of remove credential
+ test_cred_facts:
+ name: '{{ test_hostname }}'
+ type: domain_password
+ register: remove_cred_actual
+ vars: *become_vars
+
+- name: assert remove credential
+ assert:
+ that:
+ - remove_cred is changed
+ - not remove_cred_actual.exists
+
+- name: remove credential again
+ win_credential:
+ name: '{{ test_hostname }}'
+ type: domain_password
+ state: absent
+ register: remove_cred_again
+ vars: *become_vars
+
+- name: assert remove credential again
+ assert:
+ that:
+ - not remove_cred_again is changed
+
+# https://github.com/ansible/ansible/issues/67278
+- name: create credential with wildcard
+ win_credential:
+ name: '*.{{ test_hostname }}'
+ type: domain_password
+ username: DOMAIN\username
+ secret: password
+ state: present
+ persistence: enterprise
+ register: wildcard_cred
+ vars: *become_vars
+
+- name: get result of create credential with wildcard
+ test_cred_facts:
+ name: '*.{{ test_hostname }}'
+ type: domain_password
+ register: wildcard_cred_actual
+ vars: *become_vars
+
+- name: assert create credential with wildcard
+ assert:
+ that:
+ - wildcard_cred is changed
+ - wildcard_cred_actual.name == '*.' ~ test_hostname
+
+- name: remove credential with wildcard
+ win_credential:
+ name: '*.{{ test_hostname }}'
+ type: domain_password
+ state: absent
+ register: wildcard_remove
+ vars: *become_vars
+
+- name: get result of remove credential with wildcard
+ test_cred_facts:
+ name: '*.{{ test_hostname }}'
+ type: domain_password
+ register: wildcard_remove_actual
+ vars: *become_vars
+
+- name: assert remove credential with wildcard
+ assert:
+ that:
+ - wildcard_remove is changed
+ - not wildcard_remove_actual.exists
+
+- name: create generic password (check mode)
+ win_credential:
+ name: '{{ test_hostname }}'
+ type: generic_password
+ persistence: enterprise
+ username: genericuser
+ secret: genericpass
+ state: present
+ register: generic_password_check
+ check_mode: True
+ vars: *become_vars
+
+- name: get result of create generic password (check mode)
+ test_cred_facts:
+ name: '{{ test_hostname }}'
+ type: generic_password
+ register: generic_password_actual_check
+ vars: *become_vars
+
+- name: assert result of create generic password (check mode)
+ assert:
+ that:
+ - generic_password_check is changed
+ - not generic_password_actual_check.exists
+
+- name: create generic password
+ win_credential:
+ name: '{{ test_hostname }}'
+ type: generic_password
+ persistence: enterprise
+ username: genericuser
+ secret: genericpass
+ state: present
+ register: generic_password
+ vars: *become_vars
+
+- name: get result of create generic password
+ test_cred_facts:
+ name: '{{ test_hostname }}'
+ type: generic_password
+ register: generic_password_actual
+ vars: *become_vars
+
+- name: set encoded password result
+ set_fact:
+ encoded_pass: '{{ "genericpass" | string | b64encode(encoding="utf-16-le") }}'
+
+- name: assert create generic password
+ assert:
+ that:
+ - generic_password is changed
+ - generic_password_actual.exists
+ - generic_password_actual.alias == None
+ - generic_password_actual.attributes == []
+ - generic_password_actual.comment == None
+ - generic_password_actual.name == test_hostname
+ - generic_password_actual.persistence == "Enterprise"
+ - generic_password_actual.secret == encoded_pass
+ - generic_password_actual.type == "Generic"
+ - generic_password_actual.username == "genericuser"
+
+- name: create generic password again
+ win_credential:
+ name: '{{ test_hostname }}'
+ type: generic_password
+ persistence: enterprise
+ username: genericuser
+ secret: genericpass
+ state: present
+ register: generic_password_again
+ vars: *become_vars
+
+- name: assert create generic password again
+ assert:
+ that:
+ - not generic_password_again is changed
+
+- name: fail to create certificate cred with invalid thumbprint
+ win_credential:
+ name: '{{ test_hostname }}'
+ type: domain_certificate
+ username: 00112233445566778899AABBCCDDEEFF00112233
+ state: present
+ register: fail_invalid_cert
+ failed_when: fail_invalid_cert.msg != "Failed to find certificate with the thumbprint 00112233445566778899AABBCCDDEEFF00112233 in the CurrentUser\\My store"
+ vars: *become_vars
+
+- name: create domain certificate cred (check mode)
+ win_credential:
+ name: '{{ test_hostname }}'
+ type: domain_certificate
+ username: '{{ cert_thumbprint }}'
+ state: present
+ register: domain_cert_check
+ check_mode: True
+ vars: *become_vars
+
+- name: get result of create domain certificate cred (check mode)
+ test_cred_facts:
+ name: '{{ test_hostname }}'
+ type: domain_certificate
+ register: domain_cert_actual_check
+ vars: *become_vars
+
+- name: assert create domain certificate cred (check mode)
+ assert:
+ that:
+ - domain_cert_check is changed
+ - not domain_cert_actual_check.exists
+
+- name: create domain certificate cred
+ win_credential:
+ name: '{{ test_hostname }}'
+ type: domain_certificate
+ username: '{{ cert_thumbprint }}'
+ state: present
+ register: domain_cert
+ vars: *become_vars
+
+- name: get result of create domain certificate cred
+ test_cred_facts:
+ name: '{{ test_hostname }}'
+ type: domain_certificate
+ register: domain_cert_actual
+ vars: *become_vars
+
+- name: assert create domain certificate cred
+ assert:
+ that:
+ - domain_cert is changed
+ - domain_cert_actual.exists
+ - domain_cert_actual.alias == None
+ - domain_cert_actual.attributes == []
+ - domain_cert_actual.comment == None
+ - domain_cert_actual.name == test_hostname
+ - domain_cert_actual.persistence == "LocalMachine"
+ - domain_cert_actual.secret == ""
+ - domain_cert_actual.type == "DomainCertificate"
+ - domain_cert_actual.username == cert_thumbprint
+
+- name: create domain certificate cred again
+ win_credential:
+ name: '{{ test_hostname }}'
+ type: domain_certificate
+ username: '{{ cert_thumbprint }}'
+ state: present
+ register: domain_cert_again
+ vars: *become_vars
+
+- name: assert create domain certificate cred again
+ assert:
+ that:
+ - not domain_cert_again is changed
+
+- name: create generic certificate cred (check mode)
+ win_credential:
+ name: '{{ test_hostname }}'
+ type: generic_certificate
+ username: '{{ cert_thumbprint }}'
+ secret: '{{ "pin code" | b64encode }}'
+ secret_format: base64
+ state: present
+ register: generic_cert_check
+ check_mode: True
+ vars: *become_vars
+
+- name: get result of create generic certificate cred (check mode)
+ test_cred_facts:
+ name: '{{ test_hostname }}'
+ type: generic_certificate
+ register: generic_cert_actual_check
+ vars: *become_vars
+
+- name: assert create generic certificate cred (check mode)
+ assert:
+ that:
+ - generic_cert_check is changed
+ - not generic_cert_actual_check.exists
+
+- name: create generic certificate cred
+ win_credential:
+ name: '{{ test_hostname }}'
+ type: generic_certificate
+ username: '{{ cert_thumbprint }}'
+ secret: '{{ "pin code" | b64encode }}'
+ secret_format: base64
+ state: present
+ register: generic_cert
+ vars: *become_vars
+
+- name: get result of create generic certificate cred
+ test_cred_facts:
+ name: '{{ test_hostname }}'
+ type: generic_certificate
+ register: generic_cert_actual
+ vars: *become_vars
+
+- name: assert create generic certificate cred
+ assert:
+ that:
+ - generic_cert is changed
+ - generic_cert_actual.exists
+ - generic_cert_actual.alias == None
+ - generic_cert_actual.attributes == []
+ - generic_cert_actual.comment == None
+ - generic_cert_actual.name == test_hostname
+ - generic_cert_actual.persistence == "LocalMachine"
+ - generic_cert_actual.secret == "pin code" | b64encode
+ - generic_cert_actual.type == "GenericCertificate"
+ - generic_cert_actual.username == cert_thumbprint
+
+- name: create generic certificate cred again
+ win_credential:
+ name: '{{ test_hostname }}'
+ type: generic_certificate
+ username: '{{ cert_thumbprint }}'
+ state: present
+ register: generic_cert_again
+ vars: *become_vars
+
+- name: assert create generic certificate cred again
+ assert:
+ that:
+ - not generic_cert_again is changed
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/aliases b/ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/aliases
new file mode 100644
index 000000000..2a4f8cc66
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/aliases
@@ -0,0 +1,2 @@
+shippable/windows/group3
+skip/windows/2012
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/meta/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/meta/main.yml
new file mode 100644
index 000000000..9f37e96cd
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/meta/main.yml
@@ -0,0 +1,2 @@
+dependencies:
+- setup_remote_tmp_dir
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/tasks/main.yml
new file mode 100644
index 000000000..ae6be90ec
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/tasks/main.yml
@@ -0,0 +1,2 @@
+---
+- include: pre_test.yml
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/tasks/pre_test.yml b/ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/tasks/pre_test.yml
new file mode 100644
index 000000000..d63468990
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/tasks/pre_test.yml
@@ -0,0 +1,40 @@
+---
+- set_fact:
+ AnsibleVhdx: '{{ remote_tmp_dir }}\AnsiblePart.vhdx'
+
+- name: Install FS-Data-Deduplication
+ ansible.windows.win_feature:
+ name: FS-Data-Deduplication
+ include_sub_features: true
+ state: present
+ register: data_dedup_feat_reg
+
+- name: Reboot windows after the feature has been installed
+ ansible.windows.win_reboot:
+ reboot_timeout: 3600
+ when:
+ - data_dedup_feat_reg.success
+ - data_dedup_feat_reg.reboot_required
+
+- name: Copy VHDX scripts
+ ansible.windows.win_template:
+ src: "{{ item.src }}"
+ dest: '{{ remote_tmp_dir }}\{{ item.dest }}'
+ loop:
+ - { src: partition_creation_script.j2, dest: partition_creation_script.txt }
+ - { src: partition_deletion_script.j2, dest: partition_deletion_script.txt }
+
+- name: Create partition
+ ansible.windows.win_command: diskpart.exe /s {{ remote_tmp_dir }}\partition_creation_script.txt
+
+- name: Format T with NTFS
+ win_format:
+ drive_letter: T
+ file_system: ntfs
+
+- name: Run tests
+ block:
+ - include: tests.yml
+ always:
+ - name: Detach disk
+ ansible.windows.win_command: diskpart.exe /s {{ remote_tmp_dir }}\partition_deletion_script.txt
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/tasks/tests.yml
new file mode 100644
index 000000000..64a429271
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/tasks/tests.yml
@@ -0,0 +1,47 @@
+---
+
+- name: Enable Data Deduplication on the T drive - check mode
+ win_data_deduplication:
+ drive_letter: "T"
+ state: present
+ settings:
+ no_compress: true
+ minimum_file_age_days: 2
+ minimum_file_size: 0
+ check_mode: yes
+ register: win_data_deduplication_enable_check_mode
+
+- name: Check that it was successful with a change - check mode
+ assert:
+ that:
+ - win_data_deduplication_enable_check_mode is changed
+
+- name: Enable Data Deduplication on the T drive
+ win_data_deduplication:
+ drive_letter: "T"
+ state: present
+ settings:
+ no_compress: true
+ minimum_file_age_days: 2
+ minimum_file_size: 0
+ register: win_data_deduplication_enable
+
+- name: Check that it was successful with a change
+ assert:
+ that:
+ - win_data_deduplication_enable is changed
+
+- name: Enable Data Deduplication on the T drive
+ win_data_deduplication:
+ drive_letter: "T"
+ state: present
+ settings:
+ no_compress: true
+ minimum_file_age_days: 2
+ minimum_file_size: 0
+ register: win_data_deduplication_enable_again
+
+- name: Check that it was successful without a change
+ assert:
+ that:
+ - win_data_deduplication_enable_again is not changed
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/templates/partition_creation_script.j2 b/ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/templates/partition_creation_script.j2
new file mode 100644
index 000000000..8e47fda95
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/templates/partition_creation_script.j2
@@ -0,0 +1,11 @@
+create vdisk file="{{ AnsibleVhdx }}" maximum=2000 type=fixed
+
+select vdisk file="{{ AnsibleVhdx }}"
+
+attach vdisk
+
+convert mbr
+
+create partition primary
+
+assign letter="T"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/templates/partition_deletion_script.j2 b/ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/templates/partition_deletion_script.j2
new file mode 100644
index 000000000..c2be9cd14
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/templates/partition_deletion_script.j2
@@ -0,0 +1,3 @@
+select vdisk file="{{ AnsibleVhdx }}"
+
+detach vdisk
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_dhcp_lease/aliases b/ansible_collections/community/windows/tests/integration/targets/win_dhcp_lease/aliases
new file mode 100644
index 000000000..215e0b069
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_dhcp_lease/aliases
@@ -0,0 +1 @@
+shippable/windows/group4
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_dhcp_lease/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_dhcp_lease/defaults/main.yml
new file mode 100644
index 000000000..4eb43278e
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_dhcp_lease/defaults/main.yml
@@ -0,0 +1,8 @@
+---
+dhcp_lease_ip: 172.16.98.230
+dhcp_scope_id: 172.16.98.0
+dhcp_scope_start: 172.16.98.1
+dhcp_scope_end: 172.16.98.254
+dhcp_scope_subnet_mask: 255.255.255.0
+dhcp_lease_mac: 0A-0B-0C-04-05-AA
+dhcp_lease_hostname: fancy-reservation
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_dhcp_lease/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_dhcp_lease/tasks/main.yml
new file mode 100644
index 000000000..d9b36a287
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_dhcp_lease/tasks/main.yml
@@ -0,0 +1,27 @@
+---
+- block:
+ - name: Check DHCP Service/Role Install State
+ ansible.windows.win_feature:
+ name: DHCP
+ state: present
+ include_management_tools: yes
+ register: dhcp_role
+
+ - name: Reboot if Necessary
+ ansible.windows.win_reboot:
+ when: dhcp_role.reboot_required
+
+ - name: Add the DHCP scope
+ ansible.windows.win_shell: |
+ Add-DhcpServerv4Scope -Name "TestNetwork" -StartRange {{ dhcp_scope_start }} -EndRange {{dhcp_scope_end }} -SubnetMask {{ dhcp_scope_subnet_mask }}
+
+ - name: Run tests without check mode
+ include_tasks: tests.yml
+
+ - name: Run tests in check mode
+ include_tasks: tests_checkmode.yml
+
+ always:
+ - name: Remove the DHCP scope
+ ansible.windows.win_shell: |
+ Remove-DhcpServerv4Scope -ScopeId {{ dhcp_scope_id }} -Force \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_dhcp_lease/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_dhcp_lease/tasks/tests.yml
new file mode 100644
index 000000000..98bcc50ab
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_dhcp_lease/tasks/tests.yml
@@ -0,0 +1,108 @@
+---
+- name: Remove DHCP Address by IP
+ win_dhcp_lease:
+ state: absent
+ ip: "{{ dhcp_lease_ip }}"
+
+- name: Remove DHCP Address by IP (Idempotentcy Check) - Changed should equal false
+ win_dhcp_lease:
+ state: absent
+ ip: "{{ dhcp_lease_ip }}"
+ register: remove_reservation_ip
+ failed_when: remove_reservation_ip.changed != false
+
+- name: Create New DHCP Lease
+ win_dhcp_lease:
+ type: lease
+ ip: "{{ dhcp_lease_ip }}"
+ scope_id: "{{ dhcp_scope_id }}"
+ mac: "{{ dhcp_lease_mac }}"
+ dns_hostname: "{{ dhcp_lease_hostname }}"
+ dns_regtype: noreg
+ description: This is a description!
+
+- name: Create New DHCP Lease (Idempotentcy Check) - Changed should equal false
+ win_dhcp_lease:
+ type: lease
+ ip: "{{ dhcp_lease_ip }}"
+ scope_id: "{{ dhcp_scope_id }}"
+ mac: "{{ dhcp_lease_mac }}"
+ dns_hostname: "{{ dhcp_lease_hostname }}"
+ dns_regtype: noreg
+ description: This is a description!
+ register: create_lease
+ failed_when: create_lease.changed != false
+
+- name: Validate the Lease
+ ansible.windows.win_shell: |
+ Get-DhcpServerv4Scope | Get-DhcpServerv4Lease | Where-Object IPAddress -eq {{ dhcp_lease_ip }}
+ register: validate_lease_out
+ failed_when: validate_lease_out.stdout == ""
+
+- name: Convert Lease to Reservation
+ win_dhcp_lease:
+ type: reservation
+ ip: "{{ dhcp_lease_ip }}"
+
+- name: Convert Lease to Reservation (Idempotentcy Check) - Changed should equal false
+ win_dhcp_lease:
+ type: reservation
+ ip: "{{ dhcp_lease_ip }}"
+ register: convert_lease_to_reservation
+ failed_when: convert_lease_to_reservation.changed != false
+
+- name: Validate the Reservation
+ ansible.windows.win_shell: |
+ Get-DhcpServerv4Scope | Get-DhcpServerv4Reservation | Where-Object IPAddress -eq {{ dhcp_lease_ip }}
+ register: validate_reservation_out
+ failed_when: validate_reservation_out.stdout == ""
+
+- name: Update Reservation Description
+ win_dhcp_lease:
+ type: reservation
+ mac: "{{ dhcp_lease_mac }}"
+ description: Changed Description!
+
+- name: Update Reservation Description (Idempotentcy Check) - Changed should equal false
+ win_dhcp_lease:
+ type: reservation
+ mac: "{{ dhcp_lease_mac }}"
+ description: Changed Description!
+ register: update_reservation_description
+ failed_when: update_reservation_description.changed != false
+
+- name: Validate the Description
+ ansible.windows.win_shell: |
+ Get-DhcpServerv4Scope | Get-DhcpServerv4Lease | Where-Object {($_.ClientId -eq "{{ dhcp_lease_mac }}") -and ($_.Description -eq "Changed Description!")}
+ register: validate_description_out
+ failed_when: validate_description_out.stdout == ""
+
+- name: Convert Reservation to Lease
+ win_dhcp_lease:
+ type: lease
+ ip: "{{ dhcp_lease_ip }}"
+
+- name: Convert Reservation to Lease (Idempotentcy Check) - Changed should equal false
+ win_dhcp_lease:
+ type: lease
+ ip: "{{ dhcp_lease_ip }}"
+ register: convert_reservation_to_lease
+ failed_when: convert_reservation_to_lease.changed != false
+
+- name: Remove DHCP Reservation
+ win_dhcp_lease:
+ state: absent
+ mac: "{{ dhcp_lease_mac }}"
+
+- name: Remove DHCP Reservation (Idempotentcy Check) - Changed should equal false
+ win_dhcp_lease:
+ state: absent
+ mac: "{{ dhcp_lease_mac }}"
+ register: remove_reservation
+ failed_when: remove_reservation.changed != false
+
+- name: Validate the State
+ ansible.windows.win_shell: |
+ Get-DhcpServerv4Scope | Get-DhcpServerv4Reservation | Where-Object IPAddress -eq {{ dhcp_lease_ip }}
+ register: validate_state_out
+ failed_when: validate_state_out.stdout != "" \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_dhcp_lease/tasks/tests_checkmode.yml b/ansible_collections/community/windows/tests/integration/targets/win_dhcp_lease/tasks/tests_checkmode.yml
new file mode 100644
index 000000000..61f6ab5df
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_dhcp_lease/tasks/tests_checkmode.yml
@@ -0,0 +1,52 @@
+---
+- name: Check DHCP Service/Role Install State
+ ansible.windows.win_feature:
+ name: DHCP
+ state: present
+ include_management_tools: yes
+ register: dhcp_role
+ check_mode: true
+
+- name: Reboot if Necessary
+ ansible.windows.win_reboot:
+ when: dhcp_role.reboot_required
+ check_mode: true
+
+- name: Remove DHCP Address by IP
+ win_dhcp_lease:
+ state: absent
+ ip: "{{ dhcp_lease_ip }}"
+ check_mode: true
+
+- name: Create Lease
+ win_dhcp_lease:
+ type: lease
+ ip: "{{ dhcp_lease_ip }}"
+ scope_id: "{{ dhcp_scope_id }}"
+ mac: "{{ dhcp_lease_mac }}"
+ dns_hostname: "{{ dhcp_lease_hostname }}"
+ dns_regtype: noreg
+ description: This is a description!
+ check_mode: true
+
+- name: Create Reservation
+ win_dhcp_lease:
+ type: reservation
+ ip: "{{ dhcp_lease_ip }}"
+ mac: "{{ dhcp_lease_mac }}"
+ scope_id: "{{ dhcp_scope_id }}"
+ check_mode: true
+
+- name: Create Reservation w/Description
+ win_dhcp_lease:
+ type: reservation
+ ip: "{{ dhcp_lease_ip }}"
+ mac: "{{ dhcp_lease_mac }}"
+ scope_id: "{{ dhcp_scope_id }}"
+ description: This is a Description!
+ check_mode: true
+
+- name: Remove DHCP Reservation by MAC
+ win_dhcp_lease:
+ state: absent
+ mac: "{{ dhcp_lease_mac }}"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_disk_facts/aliases b/ansible_collections/community/windows/tests/integration/targets/win_disk_facts/aliases
new file mode 100644
index 000000000..e4adbabbe
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_disk_facts/aliases
@@ -0,0 +1,3 @@
+shippable/windows/group2
+skip/windows/2008 # The Storage PowerShell module was introduced in W2K12
+skip/windows/2008-R2 # The Storage PowerShell module was introduced in W2K12
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_disk_facts/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_disk_facts/tasks/main.yml
new file mode 100644
index 000000000..f1873efa7
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_disk_facts/tasks/main.yml
@@ -0,0 +1,13 @@
+# NOTE: The win_disk_facts module only works on Win2012R2+
+
+- name: check whether storage module is available (windows 2008 r2 or later)
+ ansible.windows.win_shell: '(Get-Module -Name Storage -ListAvailable | Measure-Object).Count -eq 1'
+ register: win_feature_has_storage_module
+ changed_when: false
+
+- name: Only run tests when Windows is capable
+ when: win_feature_has_storage_module.stdout | trim | bool == True
+ block:
+
+ - name: Test in normal mode
+ include: tests.yml
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_disk_facts/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_disk_facts/tasks/tests.yml
new file mode 100644
index 000000000..36d9a39e6
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_disk_facts/tasks/tests.yml
@@ -0,0 +1,89 @@
+- name: get disk facts on the target
+ win_disk_facts:
+ register: disks_found
+
+- name: assert disk facts
+ assert:
+ that:
+ - disks_found.changed == false
+ - disks_found.ansible_facts.ansible_disks[0].number is defined
+ - disks_found.ansible_facts.ansible_disks[0].guid is defined
+ - disks_found.ansible_facts.ansible_disks[0].location is defined
+ - disks_found.ansible_facts.ansible_disks[0].path is defined
+ - disks_found.ansible_facts.ansible_disks[0].read_only is defined
+ - disks_found.ansible_facts.ansible_disks[0].clustered is defined
+ - disks_found.ansible_facts.ansible_disks[0].bootable is defined
+ - disks_found.ansible_facts.ansible_disks[0].physical_disk.size is defined
+ - disks_found.ansible_facts.ansible_disks[0].physical_disk.operational_status is defined
+ - disks_found.ansible_facts.ansible_disks[0].win32_disk_drive is defined
+ - disks_found.ansible_facts.ansible_disks[0].partitions is defined
+ - disks_found.ansible_facts.ansible_disks[0].partitions[0].volumes is defined
+
+- name: get disk partition facts on the target
+ win_disk_facts:
+ filter:
+ - partitions
+ register: disks_partitions_found
+
+- name: assert partitions disk facts
+ assert:
+ that:
+ - disks_partitions_found.changed == false
+ - disks_partitions_found.ansible_facts.ansible_disks[0].partitions is defined
+
+- name: get disk volume and partition facts on the target
+ win_disk_facts:
+ filter:
+ - volumes
+ register: disks_volumes_found
+
+- name: assert volume and partition disk facts
+ assert:
+ that:
+ - disks_volumes_found.changed == false
+ - disks_volumes_found.ansible_facts.ansible_disks[0].partitions is defined
+ - disks_volumes_found.ansible_facts.ansible_disks[0].partitions[0].volumes is defined
+
+
+- name: get disk physical_disk facts on the target
+ win_disk_facts:
+ filter:
+ - physical_disk
+ register: physical_disk_found
+
+- name: assert physical_disk disk facts
+ assert:
+ that:
+ - physical_disk_found.changed == false
+ - physical_disk_found.ansible_facts.ansible_disks[0].physical_disk is defined
+
+- name: get disk virtual_disk facts on the target
+ win_disk_facts:
+ filter:
+ - virtual_disk
+ register: virtual_disk_found
+
+- name: check if virtual_disk should be found
+ ansible.windows.win_shell: |
+ if (Get-VirtualDisk){$true}else{$false}
+ register: virtual_available
+ changed_when: false
+
+- name: assert virtual_disk disk facts
+ assert:
+ that:
+ - virtual_disk_found.changed == false
+ - virtual_disk_found.ansible_facts.ansible_disks[0].virtual_disk is defined
+ when: virtual_available.stdout == "True"
+
+- name: get disk win32_disk_drive facts on the target
+ win_disk_facts:
+ filter:
+ - win32_disk_drive
+ register: win32_disk_drive_found
+
+- name: assert win32_disk_drive disk facts
+ assert:
+ that:
+ - win32_disk_drive_found.changed == false
+ - win32_disk_drive_found.ansible_facts.ansible_disks[0].win32_disk_drive is defined
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_dns_record/aliases b/ansible_collections/community/windows/tests/integration/targets/win_dns_record/aliases
new file mode 100644
index 000000000..215e0b069
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_dns_record/aliases
@@ -0,0 +1 @@
+shippable/windows/group4
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_dns_record/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_dns_record/defaults/main.yml
new file mode 100644
index 000000000..496102481
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_dns_record/defaults/main.yml
@@ -0,0 +1,3 @@
+win_dns_record_zone: test.ansible.local
+win_dns_record_revzone: 0.0.255.in-addr.arpa
+win_dns_record_revzone_network: 255.0.0.0/24
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/clean.yml b/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/clean.yml
new file mode 100644
index 000000000..29dc1cd97
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/clean.yml
@@ -0,0 +1,17 @@
+- name: Remove test zone, if present
+ ansible.windows.win_shell: |
+ $zone = '{{ item }}'
+ $fail_on_missing = '{{ fail_on_missing | default(true) }}'
+
+ Trap { If (-not $fail_on_missing) { continue } }
+ Remove-DnsServerZone -Name $zone -Force
+
+ # win_file could also do this, but it would need to know where the
+ # SystemRoot is located via fact gathering, which we cannot assume.
+ Trap { If (-not $fail_on_missing) { continue } }
+ Remove-Item -Path $env:SystemRoot\system32\dns\$zone.dns
+
+ $true # so pipeline exits cleanly if an error was ignored above
+ loop:
+ - '{{ win_dns_record_zone }}'
+ - '{{ win_dns_record_revzone }}'
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/main.yml
new file mode 100644
index 000000000..9b06a65b0
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/main.yml
@@ -0,0 +1,12 @@
+# We do an explicit OS version check here *INSTEAD OF* the usual test for
+# cmdlet existence. That's because a cmdlet test here won't work without first
+# installing the DNS feature, but we don't want to install the feature on OS'
+# that can't be supported anyway. Hence this fallback to an explicit OS version
+# test.
+- name: check OS version is supported
+ ansible.windows.win_shell: 'if ([Environment]::OSVersion.Version -ge [Version]"6.2") { $true } else { $false }'
+ register: os_supported
+
+- name: run tests on supported hosts
+ include: tests.yml
+ when: os_supported.stdout | trim | bool
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-A.yml b/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-A.yml
new file mode 100644
index 000000000..dad1d82ea
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-A.yml
@@ -0,0 +1,294 @@
+- name: 'TYPE=A - creation (check mode)'
+ win_dns_record:
+ { zone: '{{ win_dns_record_zone }}', name: test1, value: 1.2.3.4, type: A }
+ register: cmd_result
+ check_mode: yes
+
+- name: 'TYPE=A - creation get results (check mode)'
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType A -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=A - creation check results (check mode)'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'absent\r\n'
+
+- name: 'TYPE=A - creation'
+ win_dns_record:
+ { zone: '{{ win_dns_record_zone }}', name: test1, value: 1.2.3.4, type: A }
+ register: cmd_result
+
+- name: 'TYPE=A - creation get results'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType A -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty IPv4Address | Select -ExpandProperty IPAddressToString"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=A - creation check results'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == '1.2.3.4\r\n'
+
+- name: 'TYPE=A - creation (idempotent)'
+ win_dns_record:
+ { zone: '{{ win_dns_record_zone }}', name: test1, value: 1.2.3.4, type: A }
+ register: cmd_result
+
+- name: 'TYPE=A - creation get results (idempotent)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType A -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty IPv4Address | Select -ExpandProperty IPAddressToString"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=A - creation check results (idempotent)'
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == '1.2.3.4\r\n'
+
+- name: 'TYPE=A - update address (check mode)'
+ win_dns_record:
+ { zone: '{{ win_dns_record_zone }}', name: test1, value: 5.6.7.8, type: A }
+ register: cmd_result
+ check_mode: yes
+
+- name: 'TYPE=A - update address get results (check mode)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType A -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty IPv4Address | Select -ExpandProperty IPAddressToString"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=A - update address check results (check mode)'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == '1.2.3.4\r\n'
+
+- name: 'TYPE=A - update address'
+ win_dns_record:
+ { zone: '{{ win_dns_record_zone }}', name: test1, value: 5.6.7.8, type: A }
+ register: cmd_result
+
+- name: 'TYPE=A - update address get results'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType A -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty IPv4Address | Select -ExpandProperty IPAddressToString"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=A - update address check results'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == '5.6.7.8\r\n'
+
+- name: 'TYPE=A - update address (idempotent)'
+ win_dns_record:
+ { zone: '{{ win_dns_record_zone }}', name: test1, value: 5.6.7.8, type: A }
+ register: cmd_result
+
+- name: 'TYPE=A - update address get results (idempotent)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType A -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty IPv4Address | Select -ExpandProperty IPAddressToString"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=A - update address check results (idempotent)'
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == '5.6.7.8\r\n'
+
+- name: 'TYPE=A - update TTL (check mode)'
+ win_dns_record:
+ {
+ zone: '{{ win_dns_record_zone }}',
+ name: test1,
+ value: 5.6.7.8,
+ ttl: 7200,
+ type: A,
+ }
+ register: cmd_result
+ check_mode: yes
+
+- name: 'TYPE=A - update TTL get results (check mode)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType A -Node -ErrorAction:Ignore | Select -ExpandProperty TimeToLive | Select -ExpandProperty TotalSeconds"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=A - update TTL check results (check mode)'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == '3600\r\n'
+
+- name: 'TYPE=A - update TTL'
+ win_dns_record:
+ {
+ zone: '{{ win_dns_record_zone }}',
+ name: test1,
+ value: 5.6.7.8,
+ ttl: 7200,
+ type: A,
+ }
+ register: cmd_result
+
+- name: 'TYPE=A - update TTL get results'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType A -Node -ErrorAction:Ignore | Select -ExpandProperty TimeToLive | Select -ExpandProperty TotalSeconds"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=A - update TTL check results'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == '7200\r\n'
+
+- name: 'TYPE=A - update TTL (idempotent)'
+ win_dns_record:
+ {
+ zone: '{{ win_dns_record_zone }}',
+ name: test1,
+ value: 5.6.7.8,
+ ttl: 7200,
+ type: A,
+ }
+ register: cmd_result
+
+- name: 'TYPE=A - update TTL get results (idempotent)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType A -Node -ErrorAction:Ignore | Select -ExpandProperty TimeToLive | Select -ExpandProperty TotalSeconds"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=A - update TTL check results (idempotent)'
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == '7200\r\n'
+
+- name: 'TYPE=A - remove record (check mode)'
+ win_dns_record:
+ { zone: '{{ win_dns_record_zone }}', name: test1, type: A, state: absent }
+ register: cmd_result
+ check_mode: yes
+
+- name: 'TYPE=A - remove record get results (check mode)'
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType A -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=A - remove record check results (check mode)'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'exists\r\n'
+
+- name: 'TYPE=A - remove record'
+ win_dns_record:
+ { zone: '{{ win_dns_record_zone }}', name: test1, type: A, state: absent }
+ register: cmd_result
+
+- name: 'TYPE=A - remove record get results'
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType A -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=A - remove record check results'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'absent\r\n'
+
+- name: 'TYPE=A - remove record (idempotent)'
+ win_dns_record:
+ { zone: '{{ win_dns_record_zone }}', name: test1, type: A, state: absent }
+ register: cmd_result
+
+- name: 'TYPE=A - remove record get results (idempotent)'
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType A -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=A - remove record check results (idempotent)'
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == 'absent\r\n'
+
+# tests for aging
+# -----------------------------------------------------------------------------
+# create aging record
+- name: 'TYPE=A - add aging record'
+ win_dns_record:
+ zone: '{{ win_dns_record_zone }}'
+ name: testaging
+ value: 1.2.3.4
+ aging: true
+ type: A
+ state: present
+ register: cmd_result
+
+- name: 'Type=A - check if record is actually aging'
+ ansible.windows.win_command: powershell.exe "If ($null -ne (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'testaging' -RRType A).Timestamp) {'aging'} else {'not aging'}"
+ register: cmd_result_actual
+
+- name: 'TYPE=A - check aging record results'
+ ansible.builtin.assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'aging\r\n'
+
+# check idempotency
+- name: 'TYPE=A - check aging record (idempotency)'
+ win_dns_record:
+ zone: '{{ win_dns_record_zone }}'
+ name: testaging
+ value: 1.2.3.4
+ aging: true
+ type: A
+ state: present
+ register: cmd_result
+
+- name: 'TYPE=A - check aging record'
+ ansible.builtin.assert:
+ that:
+ - cmd_result is not changed
+
+# change aging attribute
+- name: 'TYPE=A - aging record (change aging)'
+ win_dns_record:
+ zone: '{{ win_dns_record_zone }}'
+ name: testaging
+ aging: false
+ value: 1.2.3.4
+ type: A
+ state: present
+ register: cmd_result
+
+- name: Type=A - check if record is not aging
+ ansible.windows.win_command: powershell.exe "If ($null -ne (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'testaging' -RRType A).Timestamp) {'aging'} else {'not aging'}"
+ register: cmd_result_actual
+
+- name: 'TYPE=A - check not aging record results'
+ ansible.builtin.assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'not aging\r\n'
+
+# remove record again
+- name: 'TYPE=A - remove record'
+ win_dns_record:
+ zone: '{{ win_dns_record_zone }}'
+ name: testaging
+ type: A
+ state: absent
+ register: cmd_result
+
+- name: 'TYPE=A - remove record get results'
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'testaging' -RRType A -Node -ErrorAction:Ignore) {'exists'} else {'absent'}"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=A - remove record check results'
+ ansible.builtin.assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'absent\r\n'
+# -----------------------------------------------------------------------------
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-AAAA.yml b/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-AAAA.yml
new file mode 100644
index 000000000..9db8ffb64
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-AAAA.yml
@@ -0,0 +1,186 @@
+- name: 'TYPE=AAAA - creation (check mode)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, value: '2001:db8::1', type: AAAA}
+ register: cmd_result
+ check_mode: yes
+
+- name: 'TYPE=AAAA - creation get results (check mode)'
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType AAAA -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=AAAA - creation check results (check mode)'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'absent\r\n'
+
+- name: 'TYPE=AAAA - creation'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, value: '2001:db8::1', type: AAAA}
+ register: cmd_result
+
+- name: 'TYPE=AAAA - creation get results'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType AAAA -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty IPv6Address | Select -ExpandProperty IPAddressToString"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=AAAA - creation check results'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == '2001:db8::1\r\n'
+
+- name: 'TYPE=AAAA - creation (idempotent)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, value: '2001:db8::1', type: AAAA}
+ register: cmd_result
+
+- name: 'TYPE=AAAA - creation get results (idempotent)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType AAAA -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty IPv6Address | Select -ExpandProperty IPAddressToString"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=AAAA - creation check results (idempotent)'
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == '2001:db8::1\r\n'
+
+
+- name: 'TYPE=AAAA - update address (check mode)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, value: '2001:db8::2', type: AAAA}
+ register: cmd_result
+ check_mode: yes
+
+- name: 'TYPE=AAAA - update address get results (check mode)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType AAAA -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty IPv6Address | Select -ExpandProperty IPAddressToString"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=AAAA - update address check results (check mode)'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == '2001:db8::1\r\n'
+
+- name: 'TYPE=AAAA - update address'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, value: '2001:db8::2', type: AAAA}
+ register: cmd_result
+
+- name: 'TYPE=AAAA - update address get results'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType AAAA -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty IPv6Address | Select -ExpandProperty IPAddressToString"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=AAAA - update address check results'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == '2001:db8::2\r\n'
+
+- name: 'TYPE=AAAA - update address (idempotent)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, value: '2001:db8::2', type: AAAA}
+ register: cmd_result
+
+- name: 'TYPE=AAAA - update address get results (idempotent)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType AAAA -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty IPv6Address | Select -ExpandProperty IPAddressToString"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=AAAA - update address check results (idempotent)'
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == '2001:db8::2\r\n'
+
+
+- name: 'TYPE=AAAA - update TTL (check mode)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, value: '2001:db8::2', ttl: 7200, type: AAAA}
+ register: cmd_result
+ check_mode: yes
+
+- name: 'TYPE=AAAA - update TTL get results (check mode)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType AAAA -Node -ErrorAction:Ignore | Select -ExpandProperty TimeToLive | Select -ExpandProperty TotalSeconds"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=AAAA - update TTL check results (check mode)'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == '3600\r\n'
+
+- name: 'TYPE=AAAA - update TTL'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, value: '2001:db8::2', ttl: 7200, type: AAAA}
+ register: cmd_result
+
+- name: 'TYPE=AAAA - update TTL get results'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType AAAA -Node -ErrorAction:Ignore | Select -ExpandProperty TimeToLive | Select -ExpandProperty TotalSeconds"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=AAAA - update TTL check results'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == '7200\r\n'
+
+- name: 'TYPE=AAAA - update address (idempotent)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, value: '2001:db8::2', ttl: 7200, type: AAAA}
+ register: cmd_result
+
+- name: 'TYPE=AAAA - update address get results (idempotent)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType AAAA -Node -ErrorAction:Ignore | Select -ExpandProperty TimeToLive | Select -ExpandProperty TotalSeconds"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=AAAA - update address check results (idempotent)'
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == '7200\r\n'
+
+
+- name: 'TYPE=AAAA - remove record (check mode)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, type: AAAA, state: absent}
+ register: cmd_result
+ check_mode: yes
+
+- name: 'TYPE=AAAA - remove record get results (check mode)'
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType AAAA -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=AAAA - remove record check results (check mode)'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'exists\r\n'
+
+- name: 'TYPE=AAAA - remove record'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, type: AAAA, state: absent}
+ register: cmd_result
+
+- name: 'TYPE=AAAA - remove record get results'
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType AAAA -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=AAAA - remove record check results'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'absent\r\n'
+
+- name: 'TYPE=AAAA - remove record (idempotent)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, type: AAAA, state: absent}
+ register: cmd_result
+
+- name: 'TYPE=AAAA - remove record get results (idempotent)'
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType AAAA -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=AAAA - remove record check results (idempotent)'
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == 'absent\r\n'
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-CNAME.yml b/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-CNAME.yml
new file mode 100644
index 000000000..d806b0a4e
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-CNAME.yml
@@ -0,0 +1,205 @@
+- name: 'TYPE=CNAME - creation (check mode)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, value: www.ansible.com, type: CNAME}
+ register: cmd_result
+ check_mode: yes
+
+- name: 'TYPE=CNAME - creation get results (check mode)'
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType CNAME -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=CNAME - creation check results (check mode)'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'absent\r\n'
+
+- name: 'TYPE=CNAME - creation'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, value: www.ansible.com, type: CNAME}
+ register: cmd_result
+
+- name: 'TYPE=CNAME - creation get results'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType CNAME -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty HostNameAlias"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=CNAME - creation check results'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'www.ansible.com.\r\n'
+
+- name: 'TYPE=CNAME - creation (idempotent)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, value: www.ansible.com, type: CNAME}
+ register: cmd_result
+
+- name: 'TYPE=CNAME - creation get results (idempotent)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType CNAME -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty HostNameAlias"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=CNAME - creation check results (idempotent)'
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == 'www.ansible.com.\r\n'
+
+
+- name: 'TYPE=CNAME - update address (check mode)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, value: docs.ansible.com, type: CNAME}
+ register: cmd_result
+ check_mode: yes
+
+- name: 'TYPE=CNAME - update address get results (check mode)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType CNAME -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty HostNameAlias"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=CNAME - update address check results (check mode)'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'www.ansible.com.\r\n'
+
+- name: 'TYPE=CNAME - update address'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, value: docs.ansible.com, type: CNAME}
+ register: cmd_result
+
+- name: 'TYPE=CNAME - update address get results'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType CNAME -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty HostNameAlias"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=CNAME - update address check results'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'docs.ansible.com.\r\n'
+
+- name: 'TYPE=CNAME - update address (idempotent)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, value: docs.ansible.com, type: CNAME}
+ register: cmd_result
+
+- name: 'TYPE=CNAME - update address get results (idempotent)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType CNAME -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty HostNameAlias"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=CNAME - update address check results (idempotent)'
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == 'docs.ansible.com.\r\n'
+
+
+- name: 'TYPE=CNAME - update TTL (check mode)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, value: docs.ansible.com, ttl: 7200, type: CNAME}
+ register: cmd_result
+ check_mode: yes
+
+- name: 'TYPE=CNAME - update TTL get results (check mode)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType CNAME -Node -ErrorAction:Ignore | Select -ExpandProperty TimeToLive | Select -ExpandProperty TotalSeconds"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=CNAME - update TTL check results (check mode)'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == '3600\r\n'
+
+- name: 'TYPE=CNAME - update TTL'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, value: docs.ansible.com, ttl: 7200, type: CNAME}
+ register: cmd_result
+
+- name: 'TYPE=CNAME - update TTL get results'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType CNAME -Node -ErrorAction:Ignore | Select -ExpandProperty TimeToLive | Select -ExpandProperty TotalSeconds"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=CNAME - update TTL check results'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == '7200\r\n'
+
+- name: 'TYPE=CNAME - update TTL (idempotent)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, value: docs.ansible.com, ttl: 7200, type: CNAME}
+ register: cmd_result
+
+- name: 'TYPE=CNAME - update TTL get results (idempotent)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType CNAME -Node -ErrorAction:Ignore | Select -ExpandProperty TimeToLive | Select -ExpandProperty TotalSeconds"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=CNAME - update TTL check results (idempotent)'
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == '7200\r\n'
+
+
+- name: 'TYPE=CNAME - remove record (check mode)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, type: CNAME, state: absent}
+ register: cmd_result
+ check_mode: yes
+
+- name: 'TYPE=CNAME - remove record get results (check mode)'
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType CNAME -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=CNAME - remove record check results (check mode)'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'exists\r\n'
+
+- name: 'TYPE=CNAME - remove record'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, type: CNAME, state: absent}
+ register: cmd_result
+
+- name: 'TYPE=CNAME - remove record get results'
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType CNAME -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=CNAME - remove record check results'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'absent\r\n'
+
+- name: 'TYPE=CNAME - remove record (idempotent)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, type: CNAME, state: absent}
+ register: cmd_result
+
+- name: 'TYPE=CNAME - remove record get results (idempotent)'
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType CNAME -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=CNAME - remove record check results (idempotent)'
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == 'absent\r\n'
+
+- name: Issue 429 - creation
+ win_dns_record:
+ name: helloworld.test
+ type: CNAME
+ value: myserver.example.com
+ zone: "{{ win_dns_record_zone }}"
+ register: cmd_result
+
+- name: Issue 429 - get results
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'helloworld.test' -RRType CNAME -Node -ErrorAction:Ignore | Select-Object -ExpandProperty RecordData | Select-Object -ExpandProperty HostNameAlias"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: Issue 429 - creation check results"
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'myserver.example.com.\r\n'
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-DHCID.yml b/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-DHCID.yml
new file mode 100644
index 000000000..2c7323ad8
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-DHCID.yml
@@ -0,0 +1,234 @@
+- name: "TYPE=DHCID - creation (check mode)"
+ win_dns_record:
+ zone: "{{ win_dns_record_zone }}"
+ name: testdhcid
+ value: "AAIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA="
+ type: DHCID
+ register: cmd_result
+ check_mode: yes
+
+- name: "TYPE=DHCID - creation get results (check mode)"
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'testdhcid' -RRType DHCID -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: "TYPE=DHCID - creation check results (check mode)"
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'absent\r\n'
+
+- name: "TYPE=DHCID - creation"
+ win_dns_record:
+ zone: "{{ win_dns_record_zone }}"
+ name: testdhcid
+ value: "AAIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA="
+ type: DHCID
+ register: cmd_result
+
+- name: "TYPE=DHCID - creation get results"
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'testdhcid' -RRType DHCID -Node -ErrorAction:Ignore | Select-Object -ExpandProperty RecordData | Select-Object -ExpandProperty DhcId"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: "TYPE=DHCID - creation check results"
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'AAIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA=\r\n'
+
+- name: "TYPE=DHCID - creation (idempotent)"
+ win_dns_record:
+ zone: "{{ win_dns_record_zone }}"
+ name: testdhcid
+ value: "AAIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA="
+ type: DHCID
+ register: cmd_result
+
+- name: "TYPE=DHCID - creation get results (idempotent)"
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'testdhcid' -RRType DHCID -Node -ErrorAction:Ignore | Select-Object -ExpandProperty RecordData | Select-Object -ExpandProperty DhcId"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: "TYPE=DHCID - creation check results (idempotent)"
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == 'AAIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA=\r\n'
+
+- name: "TYPE=DHCID - update value (check mode)"
+ win_dns_record:
+ zone: "{{ win_dns_record_zone }}"
+ name: testdhcid
+ value: "AAEBOSD+XR3Os/0LozeXVqcNc7FwCfQdWL3b/NaiUDlW2No="
+ type: DHCID
+ register: cmd_result
+ check_mode: yes
+
+- name: "TYPE=DHCID - update value get results (check mode)"
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'testdhcid' -RRType DHCID -Node -ErrorAction:Ignore | Select-Object -ExpandProperty RecordData | Select-Object -ExpandProperty DhcId"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: "TYPE=DHCID - update value check results (check mode)"
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'AAIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA=\r\n'
+
+- name: "TYPE=DHCID - update value"
+ win_dns_record:
+ zone: "{{ win_dns_record_zone }}"
+ name: testdhcid
+ value: "AAEBOSD+XR3Os/0LozeXVqcNc7FwCfQdWL3b/NaiUDlW2No="
+ type: DHCID
+ register: cmd_result
+
+- name: "TYPE=DHCID - update value get results"
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'testdhcid' -RRType DHCID -Node -ErrorAction:Ignore | Select-Object -ExpandProperty RecordData | Select-Object -ExpandProperty DhcId"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: "TYPE=DHCID - update value check results"
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'AAEBOSD+XR3Os/0LozeXVqcNc7FwCfQdWL3b/NaiUDlW2No=\r\n'
+
+- name: "TYPE=DHCID - update value (idempotent)"
+ win_dns_record:
+ zone: "{{ win_dns_record_zone }}"
+ name: testdhcid
+ value: "AAEBOSD+XR3Os/0LozeXVqcNc7FwCfQdWL3b/NaiUDlW2No="
+ type: DHCID
+ register: cmd_result
+
+- name: "TYPE=DHCID - update value get results (idempotent)"
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'testdhcid' -RRType DHCID -Node -ErrorAction:Ignore | Select-Object -ExpandProperty RecordData | Select-Object -ExpandProperty DhcId"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: "TYPE=DHCID - update value check results (idempotent)"
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == 'AAEBOSD+XR3Os/0LozeXVqcNc7FwCfQdWL3b/NaiUDlW2No=\r\n'
+
+- name: "TYPE=DHCID - update TTL (check mode)"
+ win_dns_record:
+ zone: "{{ win_dns_record_zone }}"
+ name: testdhcid
+ value: "AAEBOSD+XR3Os/0LozeXVqcNc7FwCfQdWL3b/NaiUDlW2No="
+ ttl: 7200
+ type: DHCID
+ register: cmd_result
+ check_mode: yes
+
+- name: "TYPE=DHCID - update TTL get results (check mode)"
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'testdhcid' -RRType DHCID -Node -ErrorAction:Ignore | Select-Object -ExpandProperty TimeToLive | Select-Object -ExpandProperty TotalSeconds"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: "TYPE=DHCID - update TTL check results (check mode)"
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == '3600\r\n'
+
+- name: "TYPE=DHCID - update TTL"
+ win_dns_record:
+ zone: "{{ win_dns_record_zone }}"
+ name: testdhcid
+ value: "AAEBOSD+XR3Os/0LozeXVqcNc7FwCfQdWL3b/NaiUDlW2No="
+ ttl: 7200
+ type: DHCID
+ register: cmd_result
+
+- name: "TYPE=DHCID - update TTL get results"
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'testdhcid' -RRType DHCID -Node -ErrorAction:Ignore | Select-Object -ExpandProperty TimeToLive | Select-Object -ExpandProperty TotalSeconds"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: "TYPE=DHCID - update TTL check results"
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == '7200\r\n'
+
+- name: "TYPE=DHCID - update TTL (idempotent)"
+ win_dns_record:
+ zone: "{{ win_dns_record_zone }}"
+ name: testdhcid
+ value: "AAEBOSD+XR3Os/0LozeXVqcNc7FwCfQdWL3b/NaiUDlW2No="
+ ttl: 7200
+ type: DHCID
+ register: cmd_result
+
+- name: "TYPE=DHCID - update TTL get results (idempotent)"
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'testdhcid' -RRType DHCID -Node -ErrorAction:Ignore | Select-Object -ExpandProperty TimeToLive | Select-Object -ExpandProperty TotalSeconds"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: "TYPE=DHCID - update TTL check results (idempotent)"
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == '7200\r\n'
+
+- name: "TYPE=DHCID - remove record (check mode)"
+ win_dns_record:
+ zone: "{{ win_dns_record_zone }}"
+ name: testdhcid
+ type: DHCID
+ state: absent
+ register: cmd_result
+ check_mode: yes
+
+- name: "TYPE=DHCID - remove record get results (check mode)"
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'testdhcid' -RRType DHCID -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: "TYPE=DHCID - remove record check results (check mode)"
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'exists\r\n'
+
+- name: "TYPE=DHCID - remove record"
+ win_dns_record:
+ zone: "{{ win_dns_record_zone }}"
+ name: testdhcid
+ type: DHCID
+ state: absent
+ register: cmd_result
+
+- name: "TYPE=DHCID - remove record get results"
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'testdhcid' -RRType DHCID -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: "TYPE=DHCID - remove record check results"
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'absent\r\n'
+
+- name: "TYPE=DHCID - remove record (idempotent)"
+ win_dns_record:
+ zone: "{{ win_dns_record_zone }}"
+ name: testdhcid
+ type: DHCID
+ state: absent
+ register: cmd_result
+
+- name: "TYPE=DHCID - remove record get results (idempotent)"
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'testdhcid' -RRType DHCID -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: "TYPE=DHCID - remove record check results (idempotent)"
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == 'absent\r\n'
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-NS.yml b/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-NS.yml
new file mode 100644
index 000000000..23a41da9c
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-NS.yml
@@ -0,0 +1,277 @@
+- name: 'TYPE=NS - creation (check mode)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: z, value: ansible-mirror.example.com, type: NS}
+ register: cmd_result
+ check_mode: yes
+
+- name: 'TYPE=NS - creation get results (check mode)'
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'z' -RRType NS -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=NS - creation check results (check mode)'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'absent\r\n'
+
+- name: 'TYPE=NS- creation'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: z, value: ansible-mirror.example.com, type: NS}
+ register: cmd_result
+
+- name: 'TYPE=NS - creation get results'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'z' -RRType NS -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty NameServer"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=NS - creation check results'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'ansible-mirror.example.com.\r\n'
+
+- name: 'TYPE=NS - creation (idempotent)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: z, value: ansible-mirror.example.com, type: NS}
+ register: cmd_result
+
+- name: 'TYPE=NS - creation get results (idempotent)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'z' -RRType NS -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty NameServer"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=NS - creation check results (idempotent)'
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == 'ansible-mirror.example.com.\r\n'
+
+
+- name: 'TYPE=NS - update address (check mode)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: z, value: ansible-altmirror.example.com, type: NS}
+ register: cmd_result
+ check_mode: yes
+
+- name: 'TYPE=NS - update address get results (check mode)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'z' -RRType NS -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty NameServer"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=NS - update address check results (check mode)'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'ansible-mirror.example.com.\r\n'
+
+- name: 'TYPE=NS - update address'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: z, value: ansible-altmirror.example.com, type: NS}
+ register: cmd_result
+
+- name: 'TYPE=NS - update address get results'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'z' -RRType NS -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty NameServer"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=NS - update address check results'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'ansible-altmirror.example.com.\r\n'
+
+- name: 'TYPE=NS - update address (idempotent)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: z, value: ansible-altmirror.example.com, type: NS}
+ register: cmd_result
+
+- name: 'TYPE=NS - update address get results (idempotent)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'z' -RRType NS -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty NameServer"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=NS - update address check results (idempotent)'
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == 'ansible-altmirror.example.com.\r\n'
+
+
+- name: 'TYPE=NS - update TTL (check mode)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: z, value: ansible-altmirror.example.com, ttl: 7200, type: NS}
+ register: cmd_result
+ check_mode: yes
+
+- name: 'TYPE=NS - update TTL get results (check mode)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'z' -RRType NS -Node -ErrorAction:Ignore | Select -ExpandProperty TimeToLive | Select -ExpandProperty TotalSeconds"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=NS - update TTL check results (check mode)'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == '3600\r\n'
+
+- name: 'TYPE=NS - update TTL'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: z, value: ansible-altmirror.example.com, ttl: 7200, type: NS}
+ register: cmd_result
+
+- name: 'TYPE=NS - update TTL get results'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'z' -RRType NS -Node -ErrorAction:Ignore | Select -ExpandProperty TimeToLive | Select -ExpandProperty TotalSeconds"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=NS - update TTL check results'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == '7200\r\n'
+
+- name: 'TYPE=NS - update TTL (idempotent)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: z, value: ansible-altmirror.example.com, ttl: 7200, type: NS}
+ register: cmd_result
+
+- name: 'TYPE=NS - update TTL get results (idempotent)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'z' -RRType NS -Node -ErrorAction:Ignore | Select -ExpandProperty TimeToLive | Select -ExpandProperty TotalSeconds"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=NS - update TTL check results (idempotent)'
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == '7200\r\n'
+
+- name: 'TYPE=NS - remove record (check mode)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: z, type: NS, state: absent}
+ register: cmd_result
+ check_mode: yes
+
+- name: 'TYPE=NS - remove record get results (check mode)'
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'z' -RRType NS -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=NS - remove record check results (check mode)'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'exists\r\n'
+
+- name: 'TYPE=NS - remove record'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: z, type: NS, state: absent}
+ register: cmd_result
+
+- name: 'TYPE=NS - remove record get results'
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'z' -RRType NS -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=NS - remove record check results'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'absent\r\n'
+
+- name: 'TYPE=NS - remove record (idempotent)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: z, type: NS, state: absent}
+ register: cmd_result
+
+- name: 'TYPE=NS - remove record get results (idempotent)'
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'z' -RRType NS -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=NS - remove record check results (idempotent)'
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == 'absent\r\n'
+
+- name: 'TYPE=NS - creation with multiple values (check mode)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: z, value: [ansible-mirror.example.com, ansible-altmirror.example.com, ansiblull-mirror.example.com], type: NS}
+ register: cmd_result
+ check_mode: yes
+
+- name: 'TYPE=NS - creation get results (check mode)'
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'z' -RRType NS -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=NS - creation check results (check mode)'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'absent\r\n'
+
+- name: 'TYPE=NS - creation with multiple values'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: z, value: [ansible-mirror.example.com, ansible-altmirror.example.com, ansiblull-mirror.example.com], type: NS}
+ register: cmd_result
+
+- name: 'TYPE=NS - creation get results'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'z' -RRType NS -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty NameServer"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=NS - creation check results'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'ansible-mirror.example.com.\r\nansible-altmirror.example.com.\r\nansiblull-mirror.example.com.\r\n'
+
+- name: 'TYPE=NS - creation with multiple values (idempotent)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: z, value: [ansible-mirror.example.com, ansible-altmirror.example.com, ansiblull-mirror.example.com], type: NS}
+ register: cmd_result
+
+- name: 'TYPE=NS - creation get results (idempotent)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'z' -RRType NS -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty NameServer"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=NS - creation check results (idempotent)'
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == 'ansible-mirror.example.com.\r\nansible-altmirror.example.com.\r\nansiblull-mirror.example.com.\r\n'
+
+- name: 'TYPE=NS - remove record (check mode)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: z, type: NS, state: absent}
+ register: cmd_result
+ check_mode: yes
+
+- name: 'TYPE=NS - remove record get results (check mode)'
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'z' -RRType NS -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=NS - remove record check results (check mode)'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'exists\r\n'
+
+- name: 'TYPE=NS - remove record'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: z, type: NS, state: absent}
+ register: cmd_result
+
+- name: 'TYPE=NS - remove record get results'
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'z' -RRType NS -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=NS - remove record check results'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'absent\r\n'
+
+- name: 'TYPE=NS - remove record (idempotent)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: z, type: NS, state: absent}
+ register: cmd_result
+
+- name: 'TYPE=NS - remove record get results (idempotent)'
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'z' -RRType NS -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=NS - remove record check results (idempotent)'
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == 'absent\r\n' \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-PTR.yml b/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-PTR.yml
new file mode 100644
index 000000000..796846f23
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-PTR.yml
@@ -0,0 +1,186 @@
+- name: 'TYPE=PTR - creation (check mode)'
+ win_dns_record: {zone: '{{ win_dns_record_revzone }}', name: 7, value: ansible-mirror.example.com, type: PTR}
+ register: cmd_result
+ check_mode: yes
+
+- name: 'TYPE=PTR - creation get results (check mode)'
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_revzone }}' -Name '7' -RRType PTR -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=PTR - creation check results (check mode)'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'absent\r\n'
+
+- name: 'TYPE=PTR - creation'
+ win_dns_record: {zone: '{{ win_dns_record_revzone }}', name: 7, value: ansible-mirror.example.com, type: PTR}
+ register: cmd_result
+
+- name: 'TYPE=PTR - creation get results'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_revzone }}' -Name '7' -RRType PTR -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty PtrDomainName"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=PTR - creation check results'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'ansible-mirror.example.com.\r\n'
+
+- name: 'TYPE=PTR - creation (idempotent)'
+ win_dns_record: {zone: '{{ win_dns_record_revzone }}', name: 7, value: ansible-mirror.example.com, type: PTR}
+ register: cmd_result
+
+- name: 'TYPE=PTR - creation get results (idempotent)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_revzone }}' -Name '7' -RRType PTR -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty PtrDomainName"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=PTR - creation check results (idempotent)'
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == 'ansible-mirror.example.com.\r\n'
+
+
+- name: 'TYPE=PTR - update address (check mode)'
+ win_dns_record: {zone: '{{ win_dns_record_revzone }}', name: 7, value: ansible-altmirror.example.com, type: PTR}
+ register: cmd_result
+ check_mode: yes
+
+- name: 'TYPE=PTR - update address get results (check mode)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_revzone }}' -Name '7' -RRType PTR -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty PtrDomainName"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=PTR - update address check results (check mode)'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'ansible-mirror.example.com.\r\n'
+
+- name: 'TYPE=PTR - update address'
+ win_dns_record: {zone: '{{ win_dns_record_revzone }}', name: 7, value: ansible-altmirror.example.com, type: PTR}
+ register: cmd_result
+
+- name: 'TYPE=PTR - update address get results'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_revzone }}' -Name '7' -RRType PTR -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty PtrDomainName"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=PTR - update address check results'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'ansible-altmirror.example.com.\r\n'
+
+- name: 'TYPE=PTR - update address (idempotent)'
+ win_dns_record: {zone: '{{ win_dns_record_revzone }}', name: 7, value: ansible-altmirror.example.com, type: PTR}
+ register: cmd_result
+
+- name: 'TYPE=PTR - update address get results (idempotent)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_revzone }}' -Name '7' -RRType PTR -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty PtrDomainName"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=PTR - update address check results (idempotent)'
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == 'ansible-altmirror.example.com.\r\n'
+
+
+- name: 'TYPE=PTR - update TTL (check mode)'
+ win_dns_record: {zone: '{{ win_dns_record_revzone }}', name: 7, value: ansible-altmirror.example.com, ttl: 7200, type: PTR}
+ register: cmd_result
+ check_mode: yes
+
+- name: 'TYPE=PTR - update TTL get results (check mode)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_revzone }}' -Name '7' -RRType PTR -Node -ErrorAction:Ignore | Select -ExpandProperty TimeToLive | Select -ExpandProperty TotalSeconds"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=PTR - update TTL check results (check mode)'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == '3600\r\n'
+
+- name: 'TYPE=PTR - update TTL'
+ win_dns_record: {zone: '{{ win_dns_record_revzone }}', name: 7, value: ansible-altmirror.example.com, ttl: 7200, type: PTR}
+ register: cmd_result
+
+- name: 'TYPE=PTR - update TTL get results'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_revzone }}' -Name '7' -RRType PTR -Node -ErrorAction:Ignore | Select -ExpandProperty TimeToLive | Select -ExpandProperty TotalSeconds"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=PTR - update TTL check results'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == '7200\r\n'
+
+- name: 'TYPE=PTR - update TTL (idempotent)'
+ win_dns_record: {zone: '{{ win_dns_record_revzone }}', name: 7, value: ansible-altmirror.example.com, ttl: 7200, type: PTR}
+ register: cmd_result
+
+- name: 'TYPE=PTR - update TTL get results (idempotent)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_revzone }}' -Name '7' -RRType PTR -Node -ErrorAction:Ignore | Select -ExpandProperty TimeToLive | Select -ExpandProperty TotalSeconds"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=PTR - update TTL check results (idempotent)'
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == '7200\r\n'
+
+
+- name: 'TYPE=PTR - remove record (check mode)'
+ win_dns_record: {zone: '{{ win_dns_record_revzone }}', name: 7, type: PTR, state: absent}
+ register: cmd_result
+ check_mode: yes
+
+- name: 'TYPE=PTR - remove record get results (check mode)'
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_revzone }}' -Name '7' -RRType PTR -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=PTR - remove record check results (check mode)'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'exists\r\n'
+
+- name: 'TYPE=PTR - remove record'
+ win_dns_record: {zone: '{{ win_dns_record_revzone }}', name: 7, type: PTR, state: absent}
+ register: cmd_result
+
+- name: 'TYPE=PTR - remove record get results'
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_revzone }}' -Name '7' -RRType PTR -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=PTR - remove record check results'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'absent\r\n'
+
+- name: 'TYPE=PTR - remove record (idempotent)'
+ win_dns_record: {zone: '{{ win_dns_record_revzone }}', name: 7, type: PTR, state: absent}
+ register: cmd_result
+
+- name: 'TYPE=PTR - remove record get results (idempotent)'
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_revzone }}' -Name '7' -RRType PTR -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=PTR - remove record check results (idempotent)'
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == 'absent\r\n'
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-SRV.yml b/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-SRV.yml
new file mode 100644
index 000000000..bad563565
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-SRV.yml
@@ -0,0 +1,321 @@
+- name: 'TYPE=SRV - creation (check mode)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, value: ansible.example.com, weight: 5, priority: 2, port: 755, type: SRV}
+ register: cmd_result
+ check_mode: yes
+
+- name: 'TYPE=SRV - creation get results (check mode)'
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType SRV -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=SRV - creation check results (check mode)'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'absent\r\n'
+
+- name: 'TYPE=SRV - creation'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, value: ansible.example.com, weight: 5, priority: 2, port: 755, type: SRV}
+ register: cmd_result
+
+- name: 'TYPE=SRV - creation get results'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType SRV -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty DomainName"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=SRV - creation check results'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'ansible.example.com.\r\n'
+
+- name: 'TYPE=SRV - creation (idempotent)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, value: ansible.example.com, weight: 5, priority: 2, port: 755, type: SRV}
+ register: cmd_result
+
+- name: 'TYPE=SRV - creation get results (idempotent)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType SRV -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty DomainName"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=SRV - creation check results (idempotent)'
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == 'ansible.example.com.\r\n'
+
+- name: 'TYPE=SRV - update address (check mode)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, value: altansible.example.com, weight: 5, priority: 2, port: 755, type: SRV}
+ register: cmd_result
+ check_mode: yes
+
+- name: 'TYPE=SRV - update address get results (check mode)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType SRV -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty DomainName"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=SRV - update address check results (check mode)'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'ansible.example.com.\r\n'
+
+- name: 'TYPE=SRV - update address'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, value: altansible.example.com, weight: 5, priority: 2, port: 755, type: SRV}
+ register: cmd_result
+
+- name: 'TYPE=SRV - update address get results'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType SRV -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty DomainName"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=SRV - update address check results'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'altansible.example.com.\r\n'
+
+- name: 'TYPE=SRV - update address (idempotent)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, value: altansible.example.com, weight: 5, priority: 2, port: 755, type: SRV}
+ register: cmd_result
+
+- name: 'TYPE=SRV - update address get results (idempotent)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType SRV -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty DomainName"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=SRV - update address check results (idempotent)'
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == 'altansible.example.com.\r\n'
+
+- name: 'TYPE=SRV - update TTL (check mode)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, value: altansible.example.com, weight: 5, priority: 2, port: 755, ttl: 7200, type: SRV}
+ register: cmd_result
+ check_mode: yes
+
+- name: 'TYPE=SRV - update TTL get results (check mode)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType SRV -Node -ErrorAction:Ignore | Select -ExpandProperty TimeToLive | Select -ExpandProperty TotalSeconds"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=SRV - update TTL check results (check mode)'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == '3600\r\n'
+
+- name: 'TYPE=SRV - update TTL'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, value: altansible.example.com, weight: 5, priority: 2, port: 755, ttl: 7200, type: SRV}
+ register: cmd_result
+
+- name: 'TYPE=SRV - update TTL get results'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType SRV -Node -ErrorAction:Ignore | Select -ExpandProperty TimeToLive | Select -ExpandProperty TotalSeconds"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=SRV - update TTL check results'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == '7200\r\n'
+
+- name: 'TYPE=SRV - update TTL (idempotent)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, value: altansible.example.com, weight: 5, priority: 2, port: 755, ttl: 7200, type: SRV}
+ register: cmd_result
+
+- name: 'TYPE=SRV - update TTL get results (idempotent)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType SRV -Node -ErrorAction:Ignore | Select -ExpandProperty TimeToLive | Select -ExpandProperty TotalSeconds"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=SRV - update TTL check results (idempotent)'
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == '7200\r\n'
+
+- name: 'TYPE=SRV - update weight (check mode)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, value: altansible.example.com, weight: 1, priority: 2, port: 755, type: SRV}
+ register: cmd_result
+ check_mode: yes
+
+- name: 'TYPE=SRV - update weight get results (check mode)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType SRV -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty Weight"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=SRV - update weight check results (check mode)'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == '5\r\n'
+
+- name: 'TYPE=SRV - update weight'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, weight: 1, priority: 2, port: 755, value: altansible.example.com, type: SRV}
+ register: cmd_result
+
+- name: 'TYPE=SRV - update weight get results'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType SRV -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty Weight"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=SRV - update weight check results'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == '1\r\n'
+
+- name: 'TYPE=SRV - update weight (idempotent)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, value: altansible.example.com, weight: 1, priority: 2, port: 755, type: SRV}
+ register: cmd_result
+
+- name: 'TYPE=SRV - update weight get results (idempotent)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType SRV -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty Weight"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=SRV - update weight check results (idempotent)'
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == '1\r\n'
+
+- name: 'TYPE=SRV - update port (check mode)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, value: altansible.example.com, weight: 1, priority: 2, port: 355, type: SRV}
+ register: cmd_result
+ check_mode: yes
+
+- name: 'TYPE=SRV - update port get results (check mode)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType SRV -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty Port"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=SRV - update port check results (check mode)'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == '755\r\n'
+
+- name: 'TYPE=SRV - update port'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, weight: 1, priority: 2, port: 355, value: altansible.example.com, type: SRV}
+ register: cmd_result
+
+- name: 'TYPE=SRV - update port get results'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType SRV -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty Port"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=SRV - update port check results'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == '355\r\n'
+
+- name: 'TYPE=SRV - update port (idempotent)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, value: altansible.example.com, weight: 1, priority: 2, port: 355, type: SRV}
+ register: cmd_result
+
+- name: 'TYPE=SRV - update port get results (idempotent)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType SRV -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty Port"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=SRV - update port check results (idempotent)'
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == '355\r\n'
+
+- name: 'TYPE=SRV - update priority (check mode)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, value: altansible.example.com, weight: 1, priority: 7, port: 355, type: SRV}
+ register: cmd_result
+ check_mode: yes
+
+- name: 'TYPE=SRV - update priority get results (check mode)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType SRV -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty Priority"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=SRV - update priority check results (check mode)'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == '2\r\n'
+
+- name: 'TYPE=SRV - update priority'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, weight: 1, priority: 7, port: 355, value: altansible.example.com, type: SRV}
+ register: cmd_result
+
+- name: 'TYPE=SRV - update priority get results'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType SRV -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty Priority"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=SRV - update priority check results'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == '7\r\n'
+
+- name: 'TYPE=SRV - update priority (idempotent)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, value: altansible.example.com, weight: 1, priority: 7, port: 355, type: SRV}
+ register: cmd_result
+
+- name: 'TYPE=SRV - update priority get results (idempotent)'
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType SRV -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty Priority"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=SRV - update priority check results (idempotent)'
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == '7\r\n'
+
+- name: 'TYPE=SRV - remove record (check mode)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, weight: 1, priority: 7, port: 355, type: SRV, state: absent}
+ register: cmd_result
+ check_mode: yes
+
+- name: 'TYPE=SRV - remove record get results (check mode)'
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType SRV -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=SRV - remove record check results (check mode)'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'exists\r\n'
+
+- name: 'TYPE=SRV - remove record'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, weight: 1, priority: 7, port: 355, type: SRV, state: absent}
+ register: cmd_result
+
+- name: 'TYPE=SRV - remove record get results'
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType SRV -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=SRV - remove record check results'
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'absent\r\n'
+
+- name: 'TYPE=SRV - remove record (idempotent)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: test1, weight: 1, priority: 7, port: 355, type: SRV, state: absent}
+ register: cmd_result
+
+- name: 'TYPE=SRV - remove record get results (idempotent)'
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'test1' -RRType SRV -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: 'TYPE=SRV - remove record check results (idempotent)'
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == 'absent\r\n' \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-TXT.yml b/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-TXT.yml
new file mode 100644
index 000000000..9ca6bb7fa
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-TXT.yml
@@ -0,0 +1,234 @@
+- name: "TYPE=TXT - creation (check mode)"
+ win_dns_record:
+ zone: "{{ win_dns_record_zone }}"
+ name: testtxt
+ value: txtrecordvalue
+ type: TXT
+ register: cmd_result
+ check_mode: yes
+
+- name: "TYPE=TXT - creation get results (check mode)"
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'testtxt' -RRType TXT -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: "TYPE=TXT - creation check results (check mode)"
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'absent\r\n'
+
+- name: "TYPE=TXT - creation"
+ win_dns_record:
+ zone: "{{ win_dns_record_zone }}"
+ name: testtxt
+ value: txtrecordvalue
+ type: TXT
+ register: cmd_result
+
+- name: "TYPE=TXT - creation get results"
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'testtxt' -RRType TXT -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty DescriptiveText"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: "TYPE=TXT - creation check results"
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'txtrecordvalue\r\n'
+
+- name: "TYPE=TXT - creation (idempotent)"
+ win_dns_record:
+ zone: "{{ win_dns_record_zone }}"
+ name: testtxt
+ value: txtrecordvalue
+ type: TXT
+ register: cmd_result
+
+- name: "TYPE=TXT - creation get results (idempotent)"
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'testtxt' -RRType TXT -Node -ErrorAction:Ignore | Select -ExpandProperty RecordData | Select -ExpandProperty DescriptiveText"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: "TYPE=TXT - creation check results (idempotent)"
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == 'txtrecordvalue\r\n'
+
+- name: "TYPE=TXT - update value (check mode)"
+ win_dns_record:
+ zone: "{{ win_dns_record_zone }}"
+ name: testtxt
+ value: updated txt record value
+ type: TXT
+ register: cmd_result
+ check_mode: yes
+
+- name: "TYPE=TXT - update value get results (check mode)"
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'testtxt' -RRType TXT -Node -ErrorAction:Ignore | Select-Object -ExpandProperty RecordData | Select-Object -ExpandProperty DescriptiveText"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: "TYPE=TXT - update value check results (check mode)"
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'txtrecordvalue\r\n'
+
+- name: "TYPE=TXT - update value"
+ win_dns_record:
+ zone: "{{ win_dns_record_zone }}"
+ name: testtxt
+ value: updated txt record value
+ type: TXT
+ register: cmd_result
+
+- name: "TYPE=TXT - update value get results"
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'testtxt' -RRType TXT -Node -ErrorAction:Ignore | Select-Object -ExpandProperty RecordData | Select-Object -ExpandProperty DescriptiveText"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: "TYPE=TXT - update value check results"
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'updated txt record value\r\n'
+
+- name: "TYPE=TXT - update value (idempotent)"
+ win_dns_record:
+ zone: "{{ win_dns_record_zone }}"
+ name: testtxt
+ value: updated txt record value
+ type: TXT
+ register: cmd_result
+
+- name: "TYPE=TXT - update value get results (idempotent)"
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'testtxt' -RRType TXT -Node -ErrorAction:Ignore | Select-Object -ExpandProperty RecordData | Select-Object -ExpandProperty DescriptiveText"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: "TYPE=TXT - update value check results (idempotent)"
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == 'updated txt record value\r\n'
+
+- name: "TYPE=TXT - update TTL (check mode)"
+ win_dns_record:
+ zone: "{{ win_dns_record_zone }}"
+ name: testtxt
+ value: updated txt record value
+ ttl: 7200
+ type: TXT
+ register: cmd_result
+ check_mode: true
+
+- name: "TYPE=TXT - update TTL get results (check mode)"
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'testtxt' -RRType TXT -Node -ErrorAction:Ignore | Select-Object -ExpandProperty TimeToLive | Select-Object -ExpandProperty TotalSeconds"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: "TYPE=TXT - update TTL check results (check mode)"
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == '3600\r\n'
+
+- name: "TYPE=TXT - update TTL"
+ win_dns_record:
+ zone: "{{ win_dns_record_zone }}"
+ name: testtxt
+ value: updated txt record value
+ ttl: 7200
+ type: TXT
+ register: cmd_result
+
+- name: "TYPE=TXT - update TTL get results"
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'testtxt' -RRType TXT -Node -ErrorAction:Ignore | Select-Object -ExpandProperty TimeToLive | Select-Object -ExpandProperty TotalSeconds"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: "TYPE=TXT - update TTL check results"
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == '7200\r\n'
+
+- name: "TYPE=TXT - update TTL (idempotent)"
+ win_dns_record:
+ zone: "{{ win_dns_record_zone }}"
+ name: testtxt
+ value: updated txt record value
+ ttl: 7200
+ type: TXT
+ register: cmd_result
+
+- name: "TYPE=TXT - update TTL get results (idempotent)"
+ ansible.windows.win_command: powershell.exe "Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'testtxt' -RRType TXT -Node -ErrorAction:Ignore | Select-Object -ExpandProperty TimeToLive | Select-Object -ExpandProperty TotalSeconds"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: "TYPE=TXT - update TTL check results (idempotent)"
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == '7200\r\n'
+
+- name: "TYPE=TXT - remove record (check mode)"
+ win_dns_record:
+ zone: "{{ win_dns_record_zone }}"
+ name: testtxt
+ type: TXT
+ state: absent
+ register: cmd_result
+ check_mode: yes
+
+- name: "TYPE=TXT - remove record get results (check mode)"
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'testtxt' -RRType TXT -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: "TYPE=TXT - remove record check results (check mode)"
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'exists\r\n'
+
+- name: "TYPE=TXT - remove record"
+ win_dns_record:
+ zone: "{{ win_dns_record_zone }}"
+ name: testtxt
+ type: TXT
+ state: absent
+ register: cmd_result
+
+- name: "TYPE=TXT - remove record get results"
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'testtxt' -RRType TXT -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: "TYPE=TXT - remove record check results"
+ assert:
+ that:
+ - cmd_result is changed
+ - cmd_result_actual.stdout == 'absent\r\n'
+
+- name: "TYPE=TXT - remove record (idempotent)"
+ win_dns_record:
+ zone: "{{ win_dns_record_zone }}"
+ name: testtxt
+ type: TXT
+ state: absent
+ register: cmd_result
+
+- name: "TYPE=TXT - remove record get results (idempotent)"
+ ansible.windows.win_command: powershell.exe "If (Get-DnsServerResourceRecord -ZoneName '{{ win_dns_record_zone }}' -Name 'testtxt' -RRType TXT -Node -ErrorAction:Ignore) { 'exists' } else { 'absent' }"
+ register: cmd_result_actual
+ changed_when: false
+
+- name: "TYPE=TXT - remove record check results (idempotent)"
+ assert:
+ that:
+ - cmd_result is not changed
+ - cmd_result_actual.stdout == 'absent\r\n'
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-diff.yml b/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-diff.yml
new file mode 100644
index 000000000..f5adaf369
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests-diff.yml
@@ -0,0 +1,63 @@
+# Diff tests are present because those records have to be created MANUALLY by
+# the win_dns_record module when in check mode, as there is otherwise no way in
+# Windows DNS to *simulate* a record or change.
+
+
+- name: 'Diff test - creation (check mode)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: diff_host, value: 1.2.3.4, type: A}
+ register: create_check
+ check_mode: yes
+ diff: yes
+
+- name: 'Diff test - creation'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: diff_host, value: 1.2.3.4, type: A}
+ register: create_do
+ diff: yes
+
+- name: 'Diff test - creation check results'
+ assert:
+ that:
+ - create_check.diff.before == create_do.diff.before
+ - create_check.diff.before == ''
+ - create_check.diff.after == create_do.diff.after
+ - create_check.diff.after == "[{{ win_dns_record_zone }}] diff_host 3600 IN A 1.2.3.4\n"
+
+
+- name: 'Diff test - update TTL (check mode)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: diff_host, value: 1.2.3.4, type: A, ttl: 7200}
+ register: update_check
+ check_mode: yes
+ diff: yes
+
+- name: 'Diff test - update TTL'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: diff_host, value: 1.2.3.4, type: A, ttl: 7200}
+ register: update_do
+ diff: yes
+
+- name: 'Diff test - update TTL check results'
+ assert:
+ that:
+ - update_check.diff.before == update_do.diff.before
+ - update_check.diff.before == "[{{ win_dns_record_zone }}] diff_host 3600 IN A 1.2.3.4\n"
+ - update_check.diff.after == update_do.diff.after
+ - update_check.diff.after == "[{{ win_dns_record_zone }}] diff_host 7200 IN A 1.2.3.4\n"
+
+
+- name: 'Diff test - deletion (check mode)'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: diff_host, type: A, state: absent}
+ register: delete_check
+ check_mode: yes
+ diff: yes
+
+- name: 'Diff test - deletion'
+ win_dns_record: {zone: '{{ win_dns_record_zone }}', name: diff_host, type: A, state: absent}
+ register: delete_do
+ diff: yes
+
+- name: 'Diff test - deletion check results'
+ assert:
+ that:
+ - delete_check.diff.before == delete_do.diff.before
+ - delete_check.diff.before == "[{{ win_dns_record_zone }}] diff_host 7200 IN A 1.2.3.4\n"
+ - delete_check.diff.after == delete_do.diff.after
+ - delete_check.diff.after == ''
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests.yml
new file mode 100644
index 000000000..bdf40799b
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/tests.yml
@@ -0,0 +1,36 @@
+- name: ensure DNS services are installed
+ ansible.windows.win_feature:
+ name: DNS
+ state: present
+ register: dns_install
+
+- name: reboot server if needed
+ ansible.windows.win_reboot:
+ when: dns_install.reboot_required
+
+- name: Clean slate
+ import_tasks: clean.yml
+ vars:
+ fail_on_missing: false
+
+- block:
+ - name: Create the forward zone
+ ansible.windows.win_shell: Add-DnsServerPrimaryZone -Name '{{ win_dns_record_zone }}' -ZoneFile '{{ win_dns_record_zone}}.dns'
+ - name: Create the reverse zone
+ ansible.windows.win_shell: Add-DnsServerPrimaryZone -NetworkID '{{ win_dns_record_revzone_network }}' -ZoneFile '{{ win_dns_record_revzone}}.dns'
+
+ - import_tasks: tests-A.yml
+ - import_tasks: tests-AAAA.yml
+ - import_tasks: tests-NS.yml
+ - import_tasks: tests-SRV.yml
+ - import_tasks: tests-CNAME.yml
+ - import_tasks: tests-DHCID.yml
+ - import_tasks: tests-PTR.yml
+ - import_tasks: tests-TXT.yml
+ - import_tasks: tests-diff.yml
+
+ always:
+ - name: Clean slate
+ import_tasks: clean.yml
+ vars:
+ fail_on_missing: true
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_dns_zone/aliases b/ansible_collections/community/windows/tests/integration/targets/win_dns_zone/aliases
new file mode 100644
index 000000000..df7c2d121
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_dns_zone/aliases
@@ -0,0 +1,2 @@
+shippable/windows/group1
+skip/windows/2012 \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_dns_zone/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_dns_zone/defaults/main.yml
new file mode 100644
index 000000000..73afd8e1b
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_dns_zone/defaults/main.yml
@@ -0,0 +1,7 @@
+---
+# Defines the test to run, possible values: 'standalone' or 'activedirectory'
+# 'standalone' installs a mock Windows DNS server and runs tests that only
+# include file backed DNS zones.
+# 'activedirectory' installs a mock AD/DNS server and runs tests that include
+# AD integrated and file backed DNS zones.
+win_dns_zone_test_type: standalone \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_dns_zone/tasks/activedirectory.yml b/ansible_collections/community/windows/tests/integration/targets/win_dns_zone/tasks/activedirectory.yml
new file mode 100644
index 000000000..fa75cf59e
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_dns_zone/tasks/activedirectory.yml
@@ -0,0 +1,306 @@
+---
+- 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!
+
+- name: Reboot
+ ansible.windows.win_reboot:
+
+- name: Ensure loopback address is set to DNS
+ ansible.windows.win_dns_client:
+ adapter_names: '*'
+ ipv4_addresses: 127.0.0.1
+
+- name: Reboot Again to Avoid DNS Bug
+ ansible.windows.win_reboot:
+
+- name: Ensure DNS zones are absent
+ win_dns_zone:
+ name: "{{ item }}"
+ state: absent
+ loop:
+ - jamals.euc.vmware.com
+ - dgemzer.euc.vmware.com
+ - wpinner.euc.vmware.com
+ - marshallb.euc.vmware.com
+ - basavaraju.euc.vmware.com
+ - virajp.euc.vmware.com
+
+- name: Ensure primary DNS zone is present
+ win_dns_zone:
+ name: wpinner.euc.vmware.com
+ replication: domain
+ type: primary
+ state: present
+ register: test1a
+ failed_when: test1a.changed == false
+
+- name: Ensure primary DNS zone is present (idempotence check)
+ win_dns_zone:
+ name: wpinner.euc.vmware.com
+ replication: domain
+ type: primary
+ state: present
+ register: test1
+ failed_when: test1 is changed
+
+- name: Ensure Active Directory integrated primary zone is present with secure updates
+ win_dns_zone:
+ name: basavaraju.euc.vmware.com
+ type: primary
+ replication: forest
+ dynamic_update: secure
+ register: test9a
+ failed_when: test9a.changed == false
+
+- name: Ensure Active Directory integrated primary zone is present with secure updates (idempotence check)
+ win_dns_zone:
+ name: basavaraju.euc.vmware.com
+ type: primary
+ replication: forest
+ dynamic_update: secure
+ register: test9
+ failed_when: test9 is changed
+
+- name: Ensure primary DNS zone is present, change replication
+ win_dns_zone:
+ name: wpinner.euc.vmware.com
+ replication: forest
+ type: primary
+ state: present
+ register: test2a
+ failed_when: test2a.changed == false
+
+- name: Ensure primary DNS zone is present, change replication (idempotence check)
+ win_dns_zone:
+ name: wpinner.euc.vmware.com
+ replication: forest
+ type: primary
+ state: present
+ register: test2
+ failed_when: test2 is changed
+
+- name: Ensure DNS zone is absent
+ win_dns_zone:
+ name: wpinner.euc.vmware.com
+ state: absent
+ register: test3a
+ failed_when: test3a.changed == false
+
+- name: Ensure DNS zone is absent (idempotence check)
+ win_dns_zone:
+ name: wpinner.euc.vmware.com
+ state: absent
+ register: test3
+ failed_when: test3 is changed
+
+- name: Ensure forwarder has specific DNS servers
+ win_dns_zone:
+ name: jamals.euc.vmware.com
+ type: forwarder
+ replication: forest
+ forwarder_timeout: 2
+ dns_servers:
+ - 10.245.51.100
+ - 10.245.51.101
+ - 10.245.51.102
+ register: test4a
+ failed_when: test4a.changed == false
+
+- name: Ensure forwarder has specific DNS servers (idempotence check)
+ win_dns_zone:
+ name: jamals.euc.vmware.com
+ type: forwarder
+ dns_servers:
+ - 10.245.51.100
+ - 10.245.51.101
+ - 10.245.51.102
+ register: test4
+ failed_when: test4 is changed
+
+- name: Ensure stub zone is configured
+ win_dns_zone:
+ name: dgemzer.euc.vmware.com
+ type: stub
+ replication: none
+ dns_servers:
+ - 10.19.20.1
+ - 10.19.20.2
+ register: test5a
+ failed_when: test5a.changed == false
+
+- name: Ensure stub zone is configured (idempotence check)
+ win_dns_zone:
+ name: dgemzer.euc.vmware.com
+ type: stub
+ replication: none
+ dns_servers:
+ - 10.19.20.1
+ - 10.19.20.2
+ register: test5
+ failed_when: test5 is changed
+
+- name: Ensure forwarder zone has updated DNS servers
+ win_dns_zone:
+ name: jamals.euc.vmware.com
+ type: forwarder
+ dns_servers:
+ - 10.10.1.150
+ - 10.10.1.151
+ register: test6a
+ failed_when: test6a.changed == false
+
+- name: Ensure forwarder zone has updated DNS servers (idempotence check)
+ win_dns_zone:
+ name: jamals.euc.vmware.com
+ type: forwarder
+ dns_servers:
+ - 10.10.1.150
+ - 10.10.1.151
+ register: test6
+ failed_when: test6 is changed
+
+- name: Ensure Active Directory integrated secondary zone is present
+ win_dns_zone:
+ name: virajp.euc.vmware.com
+ type: primary
+ replication: forest
+ dynamic_update: none
+ register: test7a
+ failed_when: test7a.changed == false
+
+- name: Ensure Active Directory integrated secondary zone is present (idempotence check)
+ win_dns_zone:
+ name: virajp.euc.vmware.com
+ type: primary
+ replication: forest
+ dynamic_update: none
+ register: test7
+ failed_when: test7 is changed
+
+- name: Ensure file backed primary zone is present
+ win_dns_zone:
+ name: marshallb.euc.vmware.com
+ type: primary
+ replication: none
+ register: test8a
+ failed_when: test8a.changed == false
+
+- name: Ensure file backed primary zone is present (idempotence check)
+ win_dns_zone:
+ name: marshallb.euc.vmware.com
+ type: primary
+ replication: none
+ register: test8
+ failed_when: test8 is changed
+
+- name: Ensure Active Directory integrated dynamic updates set to nonsecureandsecure
+ win_dns_zone:
+ name: basavaraju.euc.vmware.com
+ type: primary
+ dynamic_update: nonsecureandsecure
+ register: test10a
+ failed_when: test10a.changed == false
+
+- name: Ensure file backed primary zone has dynamic updates set to nonsecureandsecure (idempotence check)
+ win_dns_zone:
+ name: basavaraju.euc.vmware.com
+ type: primary
+ dynamic_update: nonsecureandsecure
+ register: test10
+ failed_when: test10 is changed
+
+- name: Ensure zone has dynamic update set to secure and replication set to domain
+ win_dns_zone:
+ name: basavaraju.euc.vmware.com
+ type: primary
+ dynamic_update: secure
+ replication: domain
+ register: test11a
+ failed_when: test11a.changed == false
+
+- name: Ensure zone has dynamic update set to secure and replication set to domain (idempotence check)
+ win_dns_zone:
+ name: basavaraju.euc.vmware.com
+ type: primary
+ dynamic_update: secure
+ replication: domain
+ register: test11
+ failed_when: test11 is changed
+
+- name: Ensure primary DNS zones are present (check mode)
+ win_dns_zone:
+ name: mehmoodkhap.euc.vmware.com
+ replication: domain
+ type: primary
+ check_mode: true
+ register: cm_test1
+ failed_when: cm_test1 is changed
+
+- name: Ensure primary DNS zones replicate to forest (check mode)
+ win_dns_zone:
+ name: chall.euc.vmware.com
+ replication: forest
+ type: primary
+ check_mode: true
+ register: cm_test2
+ failed_when: cm_test2 is changed
+
+- name: Ensure forwarder is present (check mode)
+ win_dns_zone:
+ name: nkini.euc.vmware.com
+ type: forwarder
+ dns_servers:
+ - 10.245.51.100
+ - 10.245.51.101
+ - 10.245.51.102
+ check_mode: true
+ register: cm_test3
+ failed_when: cm_test3 is changed
+
+- name: Ensure forwarder zone has specific DNS servers (check mode)
+ win_dns_zone:
+ name: ssanthanagopalan.euc.vmware.com
+ type: forwarder
+ dns_servers:
+ - 10.205.1.219
+ - 10.205.1.220
+ check_mode: true
+ register: cm_test4
+ failed_when: cm_test4 is changed
+
+- name: Ensure Active Directory integrated secondary zone is present (check mode)
+ win_dns_zone:
+ name: rrounsaville.euc.vmware.com
+ type: secondary
+ dns_servers:
+ - 10.205.1.219
+ - 10.205.1.220
+ replication: forest
+ dynamic_update: none
+ check_mode: true
+ register: cm_test5
+ failed_when: cm_test5 is changed
+
+- name: Ensure file backed stub zone is present (check mode)
+ win_dns_zone:
+ name: anup.euc.vmware.com
+ type: stub
+ dns_servers:
+ - 10.205.1.219
+ - 10.205.1.220
+ replication: none
+ dynamic_update: none
+ check_mode: true
+ register: cm_test6
+ failed_when: cm_test6 is changed
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_dns_zone/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_dns_zone/tasks/main.yml
new file mode 100644
index 000000000..e9bebdfcb
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_dns_zone/tasks/main.yml
@@ -0,0 +1,3 @@
+---
+- name: Run Defined Test Flow
+ include_tasks: "{{ win_dns_zone_test_type }}.yml"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_dns_zone/tasks/standalone.yml b/ansible_collections/community/windows/tests/integration/targets/win_dns_zone/tasks/standalone.yml
new file mode 100644
index 000000000..ed52cb6d4
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_dns_zone/tasks/standalone.yml
@@ -0,0 +1,251 @@
+---
+- name: Ensure AD/DNS roles are installed
+ ansible.windows.win_feature:
+ name:
+ - DNS
+ include_management_tools: true
+ include_sub_features: true
+ state: present
+ register: ensure_addns_roles
+
+- name: Ensure loopback address is set to DNS
+ ansible.windows.win_dns_client:
+ adapter_names: '*'
+ ipv4_addresses: 127.0.0.1
+
+- name: Reboot
+ ansible.windows.win_reboot:
+ when: ensure_addns_roles.reboot_required
+
+- name: Ensure DNS zones are absent
+ win_dns_zone:
+ name: "{{ item }}"
+ state: absent
+ loop:
+ - jamals.euc.vmware.com
+ - dgemzer.euc.vmware.com
+ - wpinner.euc.vmware.com
+ - marshallb.euc.vmware.com
+ - basavaraju.euc.vmware.com
+ - virajp.euc.vmware.com
+
+- name: Ensure file-backed primary DNS zone is present
+ win_dns_zone:
+ name: wpinner.euc.vmware.com
+ replication: none
+ type: primary
+ state: present
+ register: test1a
+ failed_when: test1a.changed == false
+
+- name: Ensure file-backed primary DNS zone is present (idempotence check)
+ win_dns_zone:
+ name: wpinner.euc.vmware.com
+ replication: none
+ type: primary
+ state: present
+ register: test1
+ failed_when: test1 is changed
+
+- name: Ensure file-backed primary zone is present with secure updates, generates warning
+ win_dns_zone:
+ name: basavaraju.euc.vmware.com
+ type: primary
+ replication: none
+ dynamic_update: secure
+ register: test2a
+ failed_when: test2a.changed == false
+
+- name: Ensure file-backed primary zone is present with secure updates, generates warning (idempotence check)
+ win_dns_zone:
+ name: basavaraju.euc.vmware.com
+ type: primary
+ replication: none
+ dynamic_update: secure
+ register: test2
+ failed_when: test2 is changed
+
+- name: Ensure DNS zone is absent
+ win_dns_zone:
+ name: wpinner.euc.vmware.com
+ state: absent
+ register: test3a
+ failed_when: test3a.changed == false
+
+- name: Ensure DNS zone is absent (idempotence check)
+ win_dns_zone:
+ name: wpinner.euc.vmware.com
+ state: absent
+ register: test3
+ failed_when: test3 is changed
+
+- name: Ensure file-backed forwarder has specific DNS servers
+ win_dns_zone:
+ name: jamals.euc.vmware.com
+ type: forwarder
+ replication: none
+ forwarder_timeout: 2
+ dns_servers:
+ - 10.245.51.100
+ - 10.245.51.101
+ - 10.245.51.102
+ register: test4a
+ failed_when: test4a.changed == false
+
+- name: Ensure file-backed forwarder has specific DNS servers (idempotence check)
+ win_dns_zone:
+ name: jamals.euc.vmware.com
+ type: forwarder
+ replication: none
+ dns_servers:
+ - 10.245.51.100
+ - 10.245.51.101
+ - 10.245.51.102
+ register: test4
+ failed_when: test4 is changed
+
+- name: Ensure file-backed stub zone is configured
+ win_dns_zone:
+ name: dgemzer.euc.vmware.com
+ type: stub
+ replication: none
+ dns_servers:
+ - 10.19.20.1
+ - 10.19.20.2
+ register: test5a
+ failed_when: test5a.changed == false
+
+- name: Ensure file-backed stub zone is configured (idempotence check)
+ win_dns_zone:
+ name: dgemzer.euc.vmware.com
+ type: stub
+ replication: none
+ dns_servers:
+ - 10.19.20.1
+ - 10.19.20.2
+ register: test5
+ failed_when: test5 is changed
+
+- name: Ensure file-backed forwarder zone has updated DNS servers
+ win_dns_zone:
+ name: jamals.euc.vmware.com
+ type: forwarder
+ replication: none
+ dns_servers:
+ - 10.10.1.150
+ - 10.10.1.151
+ register: test6a
+ failed_when: test6a.changed == false
+
+- name: Ensure file-backed forwarder zone has updated DNS servers (idempotence check)
+ win_dns_zone:
+ name: jamals.euc.vmware.com
+ type: forwarder
+ replication: none
+ dns_servers:
+ - 10.10.1.150
+ - 10.10.1.151
+ register: test6
+ failed_when: test6 is changed
+
+- name: Ensure file backed primary zone is present
+ win_dns_zone:
+ name: marshallb.euc.vmware.com
+ type: primary
+ replication: none
+ register: test7a
+ failed_when: test7a.changed == false
+
+- name: Ensure file backed primary zone is present (idempotence check)
+ win_dns_zone:
+ name: marshallb.euc.vmware.com
+ type: primary
+ replication: none
+ register: test7
+ failed_when: test7 is changed
+
+- name: Ensure file backed integrated dynamic updates set to none
+ win_dns_zone:
+ name: virajp.euc.vmware.com
+ type: primary
+ replication: none
+ dynamic_update: none
+ register: test8a
+ failed_when: test8a.changed == false
+
+- name: Ensure file backed primary zone has dynamic updates set to none (idempotence check)
+ win_dns_zone:
+ name: virajp.euc.vmware.com
+ type: primary
+ replication: none
+ dynamic_update: none
+ register: test8
+ failed_when: test8 is changed
+
+- name: Start Check Mode Tests
+ block:
+ - name: Ensure primary DNS zones are present (check mode)
+ win_dns_zone:
+ name: mehmoodkhap.euc.vmware.com
+ replication: none
+ type: primary
+ dynamic_update: none
+ register: cm_test1
+ failed_when: cm_test1 is changed
+
+ - name: Ensure file-backed primary DNS zone is present (check mode)
+ win_dns_zone:
+ name: chall.euc.vmware.com
+ replication: none
+ type: primary
+
+ register: cm_test2
+ failed_when: cm_test2 is changed
+
+ - name: Ensure file-backed forwarder is present (check mode)
+ win_dns_zone:
+ name: nkini.euc.vmware.com
+ replication: none
+ type: forwarder
+ dns_servers:
+ - 10.245.51.100
+ - 10.245.51.101
+ - 10.245.51.102
+ register: cm_test3
+ failed_when: cm_test3 is changed
+
+ - name: Ensure file-backed forwarder zone has specific DNS servers (check mode)
+ win_dns_zone:
+ name: ssanthanagopalan.euc.vmware.com
+ replication: none
+ type: forwarder
+ dns_servers:
+ - 10.205.1.219
+ - 10.205.1.220
+ register: cm_test4
+ failed_when: test4 is changed
+
+ - name: Ensure file-backed integrated secondary zone is present (check mode)
+ win_dns_zone:
+ name: rrounsaville.euc.vmware.com
+ type: secondary
+ dns_servers:
+ - 10.205.1.219
+ - 10.205.1.220
+ replication: none
+ dynamic_update: none
+ register: cm_test5
+ failed_when: cm_test5 is changed
+
+ - name: Ensure file-backed stub zone is present (check mode)
+ win_dns_zone:
+ name: anup.euc.vmware.com
+ type: stub
+ dns_servers:
+ - 10.205.1.219
+ - 10.205.1.220
+ replication: none
+ dynamic_update: none
+ register: cm_test6
+ failed_when: cm_test6 is changed
+ check_mode: true
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_domain_computer/aliases b/ansible_collections/community/windows/tests/integration/targets/win_domain_computer/aliases
new file mode 100644
index 000000000..ad7ccf7ad
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_domain_computer/aliases
@@ -0,0 +1 @@
+unsupported
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_domain_computer/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_domain_computer/tasks/main.yml
new file mode 100644
index 000000000..b8fe35022
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_domain_computer/tasks/main.yml
@@ -0,0 +1,478 @@
+# this won't run in Ansible's integration tests until we get a domain set up
+# these are here if someone wants to run the module tests locally on their own
+# domain.
+# Requirements:
+# Set the names in vars: on the command line, or set the following:
+# test_domain_name: The DNS name of the domain like ansible.local
+# test_ad_domain_dn: The DN of the domain like DC=ansible,DC=local
+# test_ad_computer_ou: The DN of the OU where computers will be created like OU=ou1,DC=ansible,DC=local
+#
+# This is not a traditional role, and can't be used with ansible-test. This is a playbook. To run ensure:
+# - your collections are set up and Ansible knows where to find them ($ANSIBLE_COLLECTIONS_PATHS for example)
+# - your inventory contains a host where this can run, like a domain controller
+# - connection keywords/options/vars are set properly to connect to the host
+# - the variable win_domain_computer_testing_host contains the name of the host or the group that contains it
+#
+# then call this file with ansible-playbook and any extra vars or other params you need
+---
+- name: run win_domain_users test
+ hosts: "{{ win_domain_computer_testing_host }}"
+ gather_facts: no
+ collections:
+ - community.windows
+ vars:
+ test_win_domain_computer_ldap_base: "{{ test_ad_domain_dn }}"
+ test_win_domain_computer_ou_path: "{{ test_ad_computer_ou }}"
+ test_win_domain_computer_name: "test_computer"
+ test_win_domain_domain_name: "{{ test_domain_name }}"
+ test_win_domain_computer_dns_hostname: "{{ test_win_domain_computer_name }}.{{ test_domain_name }}"
+ test_win_domain_computer_description: "{{ test_computer_description | default('description') }}"
+ tasks:
+
+ - name: ensure the computer is deleted before the test
+ win_domain_computer:
+ name: '{{ test_win_domain_computer_name }}'
+ state: absent
+ tags: always
+
+ # --------------------------------------------------------------------------
+
+ - name: Test computer with long name and distinct sam_account_name
+ tags:
+ - long_name
+ vars:
+ test_win_domain_computer_long_name: '{{ test_win_domain_computer_name }}_with_long_name'
+ test_win_domain_computer_sam_account_name: '{{ test_win_domain_computer_name }}$'
+ test_win_domain_computer_dns_hostname: "{{ test_win_domain_computer_long_name }}.{{ test_domain_name }}"
+ block:
+
+ # ----------------------------------------------------------------------
+ - name: create computer with long name and distinct sam_account_name (check mode)
+ win_domain_computer:
+ name: '{{ test_win_domain_computer_long_name }}'
+ dns_hostname: '{{ test_win_domain_computer_dns_hostname }}'
+ sam_account_name: '{{ test_win_domain_computer_sam_account_name }}'
+ ou: "{{ test_win_domain_computer_ou_path }}"
+ enabled: yes
+ state: present
+ register: create_distinct_sam_account_name
+ check_mode: yes
+
+ - name: assert create computer with long name and distinct sam_account_name (check mode)
+ assert:
+ that:
+ - create_distinct_sam_account_name is changed
+
+ - name: create computer with long name and distinct sam_account_name
+ win_domain_computer:
+ name: '{{ test_win_domain_computer_long_name }}'
+ dns_hostname: '{{ test_win_domain_computer_dns_hostname }}'
+ sam_account_name: '{{ test_win_domain_computer_sam_account_name }}'
+ ou: "{{ test_win_domain_computer_ou_path }}"
+ enabled: yes
+ state: present
+ register: create_distinct_sam_account_name
+
+ - name: get actual computer with long name and distinct sam_account_name
+ ansible.windows.win_shell: |
+ Import-Module ActiveDirectory
+ $c = Get-ADComputer -Identity '{{ test_win_domain_computer_sam_account_name }}' -ErrorAction Stop
+ if ($c.Name -ne '{{ test_win_domain_computer_long_name }}') {
+ throw 'Wrong computer name in relation to sAMAccountName'
+ }
+ register: create_distinct_sam_account_name_check
+
+ - name: (Idempotence) create computer with long name and distinct sam_account_name
+ win_domain_computer:
+ name: '{{ test_win_domain_computer_long_name }}'
+ dns_hostname: '{{ test_win_domain_computer_dns_hostname }}'
+ sam_account_name: '{{ test_win_domain_computer_sam_account_name }}'
+ ou: "{{ test_win_domain_computer_ou_path }}"
+ enabled: yes
+ state: present
+ register: create_distinct_sam_account_name_idempotence
+ check_mode: yes
+
+ - name: (Idempotence) assert create computer with long name and distinct sam_account_name
+ assert:
+ that:
+ - create_distinct_sam_account_name_idempotence is not changed
+
+ always:
+ - name: ensure the test computer is deleted after the test
+ win_domain_computer:
+ name: '{{ test_win_domain_computer_long_name }}'
+ sam_account_name: '{{ test_win_domain_computer_sam_account_name }}'
+ state: absent
+
+ # ----------------------------------------------------------------------
+
+ - name: Test offline domain join
+ tags:
+ - djoin
+ vars:
+ test_win_domain_computer_sam_account_name: '{{ test_win_domain_computer_name }}$'
+ block:
+ - name: No file with blob return
+ block:
+ - name: Create computer with offline domain join and blob return (check mode)
+ win_domain_computer:
+ name: '{{ test_win_domain_computer_name }}'
+ dns_hostname: '{{ test_win_domain_computer_dns_hostname }}'
+ sam_account_name: '{{ test_win_domain_computer_sam_account_name }}'
+ ou: "{{ test_win_domain_computer_ou_path }}"
+ description: "{{ test_computer_description }}"
+ enabled: yes
+ state: present
+ offline_domain_join: output
+ register: odj_result
+ check_mode: yes
+
+ - name: assert odj (check mode)
+ assert:
+ that:
+ - odj_result is changed
+ - odj_result.odj_blob is defined
+ - odj_result.odj_blob == ''
+ - odj_result.odj_blob_path is not defined
+ - odj_result.djoin is defined
+ - odj_result.djoin.invocation is defined
+
+ - name: Create computer with offline domain join and blob return
+ win_domain_computer:
+ name: '{{ test_win_domain_computer_name }}'
+ dns_hostname: '{{ test_win_domain_computer_dns_hostname }}'
+ sam_account_name: '{{ test_win_domain_computer_sam_account_name }}'
+ ou: "{{ test_win_domain_computer_ou_path }}"
+ description: "{{ test_computer_description }}"
+ enabled: yes
+ state: present
+ offline_domain_join: output
+ register: odj_result
+
+ - name: assert odj
+ assert:
+ that:
+ - odj_result is changed
+ - odj_result.odj_blob is defined
+ - odj_result.odj_blob != ''
+ - odj_result.odj_blob_path is not defined
+ - odj_result.djoin is defined
+ - odj_result.djoin.invocation is defined
+ - odj_result.djoin.rc is defined
+ - odj_result.djoin.rc == 0
+ - odj_result.djoin.stdout is defined
+ - odj_result.djoin.stderr is defined
+
+ - name: Create computer with offline domain join and blob return (idempotence)
+ win_domain_computer:
+ name: '{{ test_win_domain_computer_name }}'
+ dns_hostname: '{{ test_win_domain_computer_dns_hostname }}'
+ sam_account_name: '{{ test_win_domain_computer_sam_account_name }}'
+ ou: "{{ test_win_domain_computer_ou_path }}"
+ description: "{{ test_computer_description }}"
+ enabled: yes
+ state: present
+ offline_domain_join: output
+ register: odj_result
+
+ - name: assert odj
+ assert:
+ that:
+ - odj_result is not changed
+ - odj_result.odj_blob is not defined
+ - odj_result.odj_blob_path is not defined
+ - odj_result.djoin is not defined
+
+ always:
+ - name: ensure the test computer is deleted after the test
+ win_domain_computer:
+ name: '{{ test_win_domain_computer_name }}'
+ sam_account_name: '{{ test_win_domain_computer_sam_account_name }}'
+ state: absent
+
+
+ - name: File and blob return
+ vars:
+ blob_path: 'C:\Windows\Temp\blob.txt'
+ block:
+ - name: Create computer with offline domain join and blob file with return (check mode)
+ win_domain_computer:
+ name: '{{ test_win_domain_computer_name }}'
+ dns_hostname: '{{ test_win_domain_computer_dns_hostname }}'
+ sam_account_name: '{{ test_win_domain_computer_sam_account_name }}'
+ ou: "{{ test_win_domain_computer_ou_path }}"
+ description: "{{ test_computer_description }}"
+ enabled: yes
+ state: present
+ offline_domain_join: output
+ odj_blob_path: "{{ blob_path }}"
+ register: odj_result
+ check_mode: yes
+
+ - name: assert odj (check mode)
+ assert:
+ that:
+ - odj_result is changed
+ - odj_result.odj_blob is defined
+ - odj_result.odj_blob == ''
+ - odj_result.odj_blob_path is not defined
+ - odj_result.djoin is defined
+ - odj_result.djoin.invocation is defined
+
+ - name: Create computer with offline domain join and blob file with return
+ win_domain_computer:
+ name: '{{ test_win_domain_computer_name }}'
+ dns_hostname: '{{ test_win_domain_computer_dns_hostname }}'
+ sam_account_name: '{{ test_win_domain_computer_sam_account_name }}'
+ ou: "{{ test_win_domain_computer_ou_path }}"
+ description: "{{ test_computer_description }}"
+ enabled: yes
+ state: present
+ offline_domain_join: output
+ odj_blob_path: "{{ blob_path }}"
+ register: odj_result
+
+ - name: assert odj
+ assert:
+ that:
+ - odj_result is changed
+ - odj_result.odj_blob is defined
+ - odj_result.odj_blob != ''
+ - odj_result.odj_blob_path is not defined
+ - odj_result.djoin is defined
+ - odj_result.djoin.invocation is defined
+ - odj_result.djoin.rc is defined
+ - odj_result.djoin.rc == 0
+ - odj_result.djoin.stdout is defined
+ - odj_result.djoin.stderr is defined
+
+ - name: Create computer with offline domain join and blob file with return (idempotence)
+ win_domain_computer:
+ name: '{{ test_win_domain_computer_name }}'
+ dns_hostname: '{{ test_win_domain_computer_dns_hostname }}'
+ sam_account_name: '{{ test_win_domain_computer_sam_account_name }}'
+ ou: "{{ test_win_domain_computer_ou_path }}"
+ description: "{{ test_computer_description }}"
+ enabled: yes
+ state: present
+ offline_domain_join: output
+ odj_blob_path: "{{ blob_path }}"
+ register: odj_result
+
+ - name: assert odj
+ assert:
+ that:
+ - odj_result is not changed
+ - odj_result.odj_blob is not defined
+ - odj_result.odj_blob_path is not defined
+ - odj_result.djoin is not defined
+
+ always:
+ - name: ensure the test computer is deleted after the test
+ win_domain_computer:
+ name: '{{ test_win_domain_computer_name }}'
+ sam_account_name: '{{ test_win_domain_computer_sam_account_name }}'
+ state: absent
+
+ - name: ensure the blob file is deleted
+ win_shell: |
+ Remove-Item -LiteralPath '{{ blob_path }}' -Force -ErrorAction SilentlyContinue
+ exit 0
+
+ - name: Specified file return
+ vars:
+ blob_path: 'C:\Windows\Temp\blob.txt'
+ block:
+ - name: Create computer with offline domain join and blob file return with specified path (check mode)
+ win_domain_computer:
+ name: '{{ test_win_domain_computer_name }}'
+ dns_hostname: '{{ test_win_domain_computer_dns_hostname }}'
+ sam_account_name: '{{ test_win_domain_computer_sam_account_name }}'
+ ou: "{{ test_win_domain_computer_ou_path }}"
+ description: "{{ test_computer_description }}"
+ enabled: yes
+ state: present
+ offline_domain_join: path
+ odj_blob_path: "{{ blob_path }}"
+ register: odj_result
+ check_mode: yes
+
+ - name: assert odj (check mode)
+ assert:
+ that:
+ - odj_result is changed
+ - odj_result.odj_blob is defined
+ - odj_result.odj_blob == ''
+ - odj_result.odj_blob_path is defined
+ - odj_result.odj_blob_path == blob_path
+ - odj_result.djoin is defined
+ - odj_result.djoin.invocation is defined
+
+ - name: Create computer with offline domain join and blob file return with specified path
+ win_domain_computer:
+ name: '{{ test_win_domain_computer_name }}'
+ dns_hostname: '{{ test_win_domain_computer_dns_hostname }}'
+ sam_account_name: '{{ test_win_domain_computer_sam_account_name }}'
+ ou: "{{ test_win_domain_computer_ou_path }}"
+ description: "{{ test_computer_description }}"
+ enabled: yes
+ state: present
+ offline_domain_join: path
+ odj_blob_path: "{{ blob_path }}"
+ register: odj_result
+
+ - name: assert odj
+ assert:
+ that:
+ - odj_result is changed
+ - odj_result.odj_blob is defined
+ - odj_result.odj_blob == ''
+ - odj_result.odj_blob_path is defined
+ - odj_result.odj_blob_path == blob_path
+ - odj_result.djoin is defined
+ - odj_result.djoin.invocation is defined
+ - odj_result.djoin.rc is defined
+ - odj_result.djoin.rc == 0
+ - odj_result.djoin.stdout is defined
+ - odj_result.djoin.stderr is defined
+
+ - name: Test ODJ File
+ ansible.windows.win_shell: |
+ $ErrorActionPreference = 'Stop'
+ $file = '{{ odj_result.odj_blob_path }}'
+ $content = Get-Content -LiteralPath $file -Raw -Encoding Unicode
+ $trimmed = $content.TrimEnd("`0")
+ if ($content.Length -eq $trimmed.Length) { throw 'No terminating null found' }
+ # try a base64 decode to validate it is the kind of data we expect
+ $bytes = [Convert]::FromBase64String($trimmed)
+
+ - name: Create computer with offline domain join and blob file return with specified path (idempotence)
+ win_domain_computer:
+ name: '{{ test_win_domain_computer_name }}'
+ dns_hostname: '{{ test_win_domain_computer_dns_hostname }}'
+ sam_account_name: '{{ test_win_domain_computer_sam_account_name }}'
+ ou: "{{ test_win_domain_computer_ou_path }}"
+ description: "{{ test_computer_description }}"
+ enabled: yes
+ state: present
+ offline_domain_join: path
+ odj_blob_path: "{{ blob_path }}"
+ register: odj_result
+
+ - name: assert odj
+ assert:
+ that:
+ - odj_result is not changed
+ - odj_result.odj_blob is not defined
+ - odj_result.odj_blob_path is not defined
+ - odj_result.djoin is not defined
+
+ always:
+ - name: ensure the test computer is deleted after the test
+ win_domain_computer:
+ name: '{{ test_win_domain_computer_name }}'
+ sam_account_name: '{{ test_win_domain_computer_sam_account_name }}'
+ state: absent
+
+ - name: ensure the blob file is deleted
+ win_shell: |
+ Remove-Item -LiteralPath '{{ blob_path }}' -Force -ErrorAction SilentlyContinue
+ exit 0
+
+ - name: Random file return
+ block:
+ - name: Create computer with offline domain join and random blob file return (check mode)
+ win_domain_computer:
+ name: '{{ test_win_domain_computer_name }}'
+ dns_hostname: '{{ test_win_domain_computer_dns_hostname }}'
+ sam_account_name: '{{ test_win_domain_computer_sam_account_name }}'
+ ou: "{{ test_win_domain_computer_ou_path }}"
+ description: "{{ test_computer_description }}"
+ enabled: yes
+ state: present
+ offline_domain_join: path
+ register: odj_result
+ check_mode: yes
+
+ - name: assert odj (check mode)
+ assert:
+ that:
+ - odj_result is changed
+ - odj_result.odj_blob is defined
+ - odj_result.odj_blob == ''
+ - odj_result.odj_blob_path is defined
+ - odj_result.djoin is defined
+ - odj_result.djoin.invocation is defined
+
+ - name: Create computer with offline domain join and random blob file return
+ win_domain_computer:
+ name: '{{ test_win_domain_computer_name }}'
+ dns_hostname: '{{ test_win_domain_computer_dns_hostname }}'
+ sam_account_name: '{{ test_win_domain_computer_sam_account_name }}'
+ ou: "{{ test_win_domain_computer_ou_path }}"
+ description: "{{ test_computer_description }}"
+ enabled: yes
+ state: present
+ offline_domain_join: path
+ register: odj_result
+
+ - name: assert odj
+ assert:
+ that:
+ - odj_result is changed
+ - odj_result.odj_blob is defined
+ - odj_result.odj_blob == ''
+ - odj_result.odj_blob_path is defined
+ - odj_result.djoin is defined
+ - odj_result.djoin.invocation is defined
+ - odj_result.djoin.rc is defined
+ - odj_result.djoin.rc == 0
+ - odj_result.djoin.stdout is defined
+ - odj_result.djoin.stderr is defined
+
+ - name: This file needs to be deleted later
+ set_fact:
+ returned_file: "{{ odj_result.odj_blob_path }}"
+
+ - name: Test ODJ File
+ ansible.windows.win_shell: |
+ $ErrorActionPreference = 'Stop'
+ $file = '{{ odj_result.odj_blob_path }}'
+ $content = Get-Content -LiteralPath $file -Raw -Encoding Unicode
+ $trimmed = $content.TrimEnd("`0")
+ if ($content.Length -eq $trimmed.Length) { throw 'No terminating null found' }
+ # try a base64 decode to validate it is the kind of data we expect
+ $bytes = [Convert]::FromBase64String($trimmed)
+
+ - name: Create computer with offline domain join and random blob file return (idempotence)
+ win_domain_computer:
+ name: '{{ test_win_domain_computer_name }}'
+ dns_hostname: '{{ test_win_domain_computer_dns_hostname }}'
+ sam_account_name: '{{ test_win_domain_computer_sam_account_name }}'
+ ou: "{{ test_win_domain_computer_ou_path }}"
+ description: "{{ test_computer_description }}"
+ enabled: yes
+ state: present
+ offline_domain_join: path
+ register: odj_result
+
+ - name: assert odj
+ assert:
+ that:
+ - odj_result is not changed
+ - odj_result.odj_blob is not defined
+ - odj_result.odj_blob_path is not defined
+ - odj_result.djoin is not defined
+
+ always:
+ - name: ensure the test computer is deleted after the test
+ win_domain_computer:
+ name: '{{ test_win_domain_computer_name }}'
+ sam_account_name: '{{ test_win_domain_computer_sam_account_name }}'
+ state: absent
+
+ - name: ensure the blob file is deleted
+ win_shell: |
+ Remove-Item -LiteralPath '{{ returned_file }}' -Force -ErrorAction SilentlyContinue
+ exit 0
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_domain_group/aliases b/ansible_collections/community/windows/tests/integration/targets/win_domain_group/aliases
new file mode 100644
index 000000000..ad7ccf7ad
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_domain_group/aliases
@@ -0,0 +1 @@
+unsupported
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_domain_group/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_domain_group/defaults/main.yml
new file mode 100644
index 000000000..b02643ee0
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_domain_group/defaults/main.yml
@@ -0,0 +1,3 @@
+test_win_domain_group_ldap_base: DC=ansible,DC=local
+test_win_domain_group_ou_path: OU=ou1,DC=ansible,DC=local
+test_win_domain_group_name: Moo Cow
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_domain_group/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_domain_group/tasks/main.yml
new file mode 100644
index 000000000..1624928ea
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_domain_group/tasks/main.yml
@@ -0,0 +1,353 @@
+# this won't run in Ansible's integration tests until we get a domain set up
+# these are here if someone wants to run the module tests locally on their own
+# domain.
+# Requirements:
+# LDAP Base path set in defaults/main.yml like DC=ansible,DC=local
+# Custom OU path set in defaults/main.yml like OU=ou1,DC=ansible,DC=local
+---
+- name: ensure the test group is deleted before the test
+ win_domain_group:
+ name: '{{test_win_domain_group_name}}'
+ state: absent
+ ignore_protection: True
+
+- name: fail pass in an invalid path
+ win_domain_group:
+ name: '{{test_win_domain_group_name}}'
+ state: present
+ organizational_unit: OU=fakeou,{{test_win_domain_group_ldap_base}}
+ register: fail_invalid_path
+ failed_when: fail_invalid_path.msg != 'the group path OU=fakeou,' + test_win_domain_group_ldap_base + ' does not exist, please specify a valid LDAP path'
+
+- name: create group with defaults check
+ win_domain_group:
+ name: '{{test_win_domain_group_name}}'
+ scope: global
+ state: present
+ register: create_default_check
+ check_mode: yes
+
+- name: get actual group with defaults check
+ ansible.windows.win_command: powershell.exe "Import-Module ActiveDirectory; Get-ADGroup -Identity '{{test_win_domain_group_name}}'"
+ register: create_default_actual_check
+ ignore_errors: True
+
+- name: assert create group with defaults checl
+ assert:
+ that:
+ - create_default_check is changed
+ - create_default_actual_check.rc == 1
+
+- name: create group with defaults
+ win_domain_group:
+ name: '{{test_win_domain_group_name}}'
+ scope: global
+ state: present
+ register: create_default
+
+- name: get actual group with defaults
+ ansible.windows.win_command: powershell.exe "Import-Module ActiveDirectory; Get-ADGroup -Identity '{{test_win_domain_group_name}}'"
+ register: create_default_actual
+
+- name: assert create group with defaults
+ assert:
+ that:
+ - create_default is created
+ - create_default is changed
+ - create_default.category == 'Security'
+ - create_default.description == None
+ - create_default.display_name == None
+ - create_default.distinguished_name == 'CN=' + test_win_domain_group_name + ',CN=Users,' + test_win_domain_group_ldap_base
+ - create_default.group_scope == 'Global'
+ - create_default.guid is defined
+ - create_default.managed_by == None
+ - create_default.name == test_win_domain_group_name
+ - create_default.protected_from_accidental_deletion == False
+ - create_default.sid is defined
+ - create_default_actual.rc == 0
+
+- name: create group with defaults again
+ win_domain_group:
+ name: '{{test_win_domain_group_name}}'
+ scope: global
+ state: present
+ register: create_default_again
+
+- name: assert create group with defaults again
+ assert:
+ that:
+ - create_default_again is not changed
+ - create_default_again is not created
+
+- name: remove group check
+ win_domain_group:
+ name: '{{test_win_domain_group_name}}'
+ state: absent
+ register: remove_group_check
+ check_mode: yes
+
+- name: get actual remove group check
+ ansible.windows.win_command: powershell.exe "Import-Module ActiveDirectory; Get-ADGroup -Identity '{{test_win_domain_group_name}}'"
+ register: remove_group_actual_check
+
+- name: assert remove group check
+ assert:
+ that:
+ - remove_group_check is changed
+ - remove_group_actual_check.rc == 0
+
+- name: remove group
+ win_domain_group:
+ name: '{{test_win_domain_group_name}}'
+ state: absent
+ register: remove_group
+
+- name: get actual remove group
+ ansible.windows.win_command: powershell.exe "Import-Module ActiveDirectory; Get-ADGroup -Identity '{{test_win_domain_group_name}}'"
+ register: remove_group_actual
+ ignore_errors: True
+
+- name: assert remove group
+ assert:
+ that:
+ - remove_group is changed
+ - remove_group is not created
+ - remove_group_actual.rc == 1
+
+- name: remove group again
+ win_domain_group:
+ name: '{{test_win_domain_group_name}}'
+ state: absent
+ register: remove_group_again
+
+- name: assert remove group again
+ assert:
+ that:
+ - remove_group_again is not changed
+ - remove_group_again is not created
+
+- name: create non default group check
+ win_domain_group:
+ name: '{{test_win_domain_group_name}}'
+ state: present
+ description: Group Description
+ display_name: Group Display Name
+ managed_by: Domain Admins
+ organizational_unit: '{{test_win_domain_group_ou_path}}'
+ category: distribution
+ scope: domainlocal
+ attributes:
+ mail: test@email.com
+ wWWHomePage: www.google.com
+ protect: True
+ register: create_non_default_check
+ check_mode: yes
+
+- name: get actual create non default group check
+ ansible.windows.win_command: powershell.exe "Import-Module ActiveDirectory; Get-ADGroup -Identity '{{test_win_domain_group_name}}'"
+ register: create_non_default_actual_check
+ ignore_errors: True
+
+- name: assert create non default group check
+ assert:
+ that:
+ - create_non_default_check is changed
+ - create_non_default_check is created
+ - create_non_default_actual_check.rc == 1
+
+- name: create non default group
+ win_domain_group:
+ name: '{{test_win_domain_group_name}}'
+ state: present
+ description: Group Description
+ display_name: Group Display Name
+ managed_by: Domain Admins
+ organizational_unit: '{{test_win_domain_group_ou_path}}'
+ category: distribution
+ scope: domainlocal
+ attributes:
+ mail: test@email.com
+ wWWHomePage: www.google.com
+ protect: True
+ register: create_non_default
+
+- name: get actual create non default group
+ ansible.windows.win_command: powershell.exe "Import-Module ActiveDirectory; Get-ADGroup -Identity '{{test_win_domain_group_name}}'"
+ register: create_non_default_actual
+ ignore_errors: True
+
+- name: assert create non default group
+ assert:
+ that:
+ - create_non_default is changed
+ - create_non_default is created
+ - create_non_default.category == 'Distribution'
+ - create_non_default.description == 'Group Description'
+ - create_non_default.display_name == 'Group Display Name'
+ - create_non_default.distinguished_name == 'CN=' + test_win_domain_group_name + ',' + test_win_domain_group_ou_path
+ - create_non_default.group_scope == 'DomainLocal'
+ - create_non_default.guid is defined
+ - create_non_default.managed_by == 'CN=Domain Admins,CN=Users,' + test_win_domain_group_ldap_base
+ - create_non_default.name == test_win_domain_group_name
+ - create_non_default.protected_from_accidental_deletion == True
+ - create_non_default.sid is defined
+ - create_non_default.attributes.mail == 'test@email.com'
+ - create_non_default.attributes.wWWHomePage == 'www.google.com'
+ - create_non_default_actual.rc == 0
+
+- name: create non default group again
+ win_domain_group:
+ name: '{{test_win_domain_group_name}}'
+ state: present
+ description: Group Description
+ display_name: Group Display Name
+ managed_by: Domain Admins
+ organizational_unit: '{{test_win_domain_group_ou_path}}'
+ category: distribution
+ scope: domainlocal
+ attributes:
+ mail: test@email.com
+ wWWHomePage: www.google.com
+ register: create_non_default_again
+
+- name: assert create non default group again
+ assert:
+ that:
+ - create_non_default_again is not changed
+ - create_non_default_again is not created
+
+- name: try and move group with protection mode on
+ win_domain_group:
+ name: '{{test_win_domain_group_name}}'
+ state: present
+ organizational_unit: CN=Users,{{test_win_domain_group_ldap_base}}
+ register: fail_move_with_protection
+ failed_when: fail_move_with_protection.msg != 'cannot move group ' + test_win_domain_group_name + ' when ProtectedFromAccidentalDeletion is turned on, run this module with ignore_protection=true to override this'
+
+- name: modify existing group check
+ win_domain_group:
+ name: '{{test_win_domain_group_name}}'
+ state: present
+ description: New Description
+ display_name: New Display Name
+ managed_by: Administrator
+ organizational_unit: 'CN=Users,{{test_win_domain_group_ldap_base}}'
+ category: security
+ scope: global
+ attributes:
+ mail: anothertest@email.com
+ ignore_protection: True
+ register: modify_existing_check
+ check_mode: yes
+
+- name: get actual of modify existing group check
+ ansible.windows.win_command: powershell.exe "Import-Module ActiveDirectory; (Get-ADGroup -Identity '{{test_win_domain_group_name}}').DistinguishedName"
+ register: modify_existing_actual_check
+
+- name: assert modify existing group check
+ assert:
+ that:
+ - modify_existing_check is changed
+ - modify_existing_check is not created
+ - modify_existing_actual_check.stdout == 'CN=' + test_win_domain_group_name + ',' + test_win_domain_group_ou_path + '\r\n'
+
+- name: modify existing group
+ win_domain_group:
+ name: '{{test_win_domain_group_name}}'
+ state: present
+ description: New Description
+ display_name: New Display Name
+ managed_by: Administrator
+ organizational_unit: CN=Users,{{test_win_domain_group_ldap_base}}
+ category: security
+ scope: global
+ attributes:
+ mail: anothertest@email.com
+ protect: True
+ ignore_protection: True
+ register: modify_existing
+
+- name: get actual of modify existing group
+ ansible.windows.win_command: powershell.exe "Import-Module ActiveDirectory; (Get-ADGroup -Identity '{{test_win_domain_group_name}}').DistinguishedName"
+ register: modify_existing_actual
+
+- name: assert modify existing group
+ assert:
+ that:
+ - modify_existing is changed
+ - modify_existing is not created
+ - modify_existing.category == 'Security'
+ - modify_existing.description == 'New Description'
+ - modify_existing.display_name == 'New Display Name'
+ - modify_existing.distinguished_name == 'CN=' + test_win_domain_group_name + ',CN=Users,' + test_win_domain_group_ldap_base
+ - modify_existing.group_scope == 'Global'
+ - modify_existing.guid is defined
+ - modify_existing.managed_by == 'CN=Administrator,CN=Users,' + test_win_domain_group_ldap_base
+ - modify_existing.name == test_win_domain_group_name
+ - modify_existing.protected_from_accidental_deletion == True
+ - modify_existing.sid is defined
+ - modify_existing.attributes.mail == 'anothertest@email.com'
+ - modify_existing_actual.stdout == 'CN=' + test_win_domain_group_name + ',CN=Users,' + test_win_domain_group_ldap_base + '\r\n'
+
+- name: modify existing group again
+ win_domain_group:
+ name: '{{test_win_domain_group_name}}'
+ state: present
+ description: New Description
+ display_name: New Display Name
+ managed_by: Administrator
+ organizational_unit: CN=Users,{{test_win_domain_group_ldap_base}}
+ category: Security
+ scope: global
+ attributes:
+ mail: anothertest@email.com
+ protect: True
+ ignore_protection: True
+ register: modify_existing_again
+
+- name: assert modify existing group again
+ assert:
+ that:
+ - modify_existing_again is not changed
+ - modify_existing_again is not created
+
+- name: fail change managed_by to invalid user
+ win_domain_group:
+ name: '{{test_win_domain_group_name}}'
+ state: present
+ scope: global
+ managed_by: fake user
+ register: fail_invalid_managed_by_user
+ failed_when: fail_invalid_managed_by_user.msg != 'failed to find managed_by user or group fake user to be used for comparison'
+
+- name: fail delete group with protection mode on
+ win_domain_group:
+ name: '{{test_win_domain_group_name}}'
+ state: absent
+ register: fail_delete_with_protection
+ failed_when: fail_delete_with_protection.msg != 'cannot delete group ' + test_win_domain_group_name + ' when ProtectedFromAccidentalDeletion is turned on, run this module with ignore_protection=true to override this'
+
+- name: delete group with protection mode on
+ win_domain_group:
+ name: '{{test_win_domain_group_name}}'
+ state: absent
+ ignore_protection: True
+ register: delete_with_force
+
+- name: get actual delete group with protection mode on
+ ansible.windows.win_command: powershell.exe "Import-Module ActiveDirectory; Get-ADGroup -Identity '{{test_win_domain_group_name}}'"
+ register: delete_with_force_actual
+ ignore_errors: True
+
+- name: assert delete group with protection mode on
+ assert:
+ that:
+ - delete_with_force is changed
+ - delete_with_force is not created
+ - delete_with_force_actual.rc == 1
+
+- name: ensure the test group is deleted after the test
+ win_domain_group:
+ name: '{{test_win_domain_group_name}}'
+ state: absent
+ ignore_protection: True
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_domain_object_info/aliases b/ansible_collections/community/windows/tests/integration/targets/win_domain_object_info/aliases
new file mode 100644
index 000000000..ad7ccf7ad
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_domain_object_info/aliases
@@ -0,0 +1 @@
+unsupported
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_domain_object_info/handlers/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_domain_object_info/handlers/main.yml
new file mode 100644
index 000000000..76a2a0f76
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_domain_object_info/handlers/main.yml
@@ -0,0 +1,5 @@
+---
+- name: remove test domain user
+ win_domain_user:
+ name: '{{ test_user.distinguished_name }}'
+ state: absent
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_domain_object_info/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_domain_object_info/tasks/main.yml
new file mode 100644
index 000000000..89c977bfb
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_domain_object_info/tasks/main.yml
@@ -0,0 +1,125 @@
+# These tests can't run in CI, this is really just a basic smoke tests for local runs.
+---
+- name: assert better error message on auth failure
+ win_domain_object_info:
+ identity: id
+ register: fail_auth
+ failed_when: '"Failed to contact the AD server, this could be caused by the double hop problem" not in fail_auth.msg'
+ vars:
+ ansible_winrm_transport: ntlm
+ ansible_psrp_auth: ntlm
+
+- name: create test ad user
+ win_domain_user:
+ name: Ansible Test
+ firstname: Ansible
+ surname: Test
+ company: Contoso R Us
+ password: Password01
+ state: present
+ password_never_expires: yes
+ groups:
+ - Domain Users
+ enabled: false
+ register: test_user
+ notify: remove test domain user
+
+- name: set a binary attribute and return other useful info missing from above
+ ansible.windows.win_shell: |
+ Set-ADUser -Identity '{{ test_user.sid }}' -Replace @{ audio = @([byte[]]@(1, 2, 3, 4), [byte[]]@(5, 6, 7, 8)) }
+
+ $user = Get-ADUser -Identity '{{ test_user.sid }}' -Properties modifyTimestamp, ObjectGUID
+
+ [TimeZoneInfo]::ConvertTimeToUtc($user.modifyTimestamp).ToString('o')
+ $user.ObjectGUID.ToString()
+ ([System.Security.Principal.SecurityIdentifier]'{{ test_user.sid }}').Translate([System.Security.Principal.NTAccount]).Value
+ register: test_user_extras
+
+- name: set other test info for easier access
+ set_fact:
+ test_user_mod_date: '{{ test_user_extras.stdout_lines[0] }}'
+ test_user_id: '{{ test_user_extras.stdout_lines[1] }}'
+ test_user_name: '{{ test_user_extras.stdout_lines[2] }}'
+
+- name: get properties for single user by DN
+ win_domain_object_info:
+ identity: '{{ test_user.distinguished_name }}'
+ register: by_identity
+ check_mode: yes # Just verifies it runs in check mode
+
+- name: assert get properties for single user by DN
+ assert:
+ that:
+ - not by_identity is changed
+ - by_identity.objects | length == 1
+ - by_identity.objects[0].keys() | list | length == 4
+ - by_identity.objects[0].DistinguishedName == test_user.distinguished_name
+ - by_identity.objects[0].Name == 'Ansible Test'
+ - by_identity.objects[0].ObjectClass == 'user'
+ - by_identity.objects[0].ObjectGUID == test_user_id
+
+- name: get specific properties by GUID
+ win_domain_object_info:
+ identity: '{{ test_user_id }}'
+ properties:
+ - audio # byte[]
+ - company # string
+ - department # not set
+ - logonCount # int
+ - modifyTimestamp # DateTime
+ - nTSecurityDescriptor # SecurityDescriptor as SDDL
+ - objectSID # SID
+ - ProtectedFromAccidentalDeletion # bool
+ - sAMAccountType # Test out the enum string attribute that we add
+ - userAccountControl # Test ou the enum string attribute that we add
+ register: by_guid_custom_props
+
+- name: assert get specific properties by GUID
+ assert:
+ that:
+ - not by_guid_custom_props is changed
+ - by_guid_custom_props.objects | length == 1
+ - by_guid_custom_props.objects[0].DistinguishedName == test_user.distinguished_name
+ - by_guid_custom_props.objects[0].Name == 'Ansible Test'
+ - by_guid_custom_props.objects[0].ObjectClass == 'user'
+ - by_guid_custom_props.objects[0].ObjectGUID == test_user_id
+ - not by_guid_custom_props.objects[0].ProtectedFromAccidentalDeletion
+ - by_guid_custom_props.objects[0].audio == ['BQYHCA==', 'AQIDBA==']
+ - by_guid_custom_props.objects[0].company == 'Contoso R Us'
+ - by_guid_custom_props.objects[0].department == None
+ - by_guid_custom_props.objects[0].logonCount == 0
+ - by_guid_custom_props.objects[0].modifyTimestamp == test_user_mod_date
+ - by_guid_custom_props.objects[0].nTSecurityDescriptor.startswith('O:DAG:DAD:AI(')
+ - by_guid_custom_props.objects[0].objectSID.Name == test_user_name
+ - by_guid_custom_props.objects[0].objectSID.Sid == test_user.sid
+ - by_guid_custom_props.objects[0].sAMAccountType == 805306368
+ - by_guid_custom_props.objects[0].sAMAccountType_AnsibleFlags == ['SAM_USER_OBJECT']
+ - by_guid_custom_props.objects[0].userAccountControl == 66050
+ - by_guid_custom_props.objects[0].userAccountControl_AnsibleFlags == ['ADS_UF_ACCOUNTDISABLE', 'ADS_UF_NORMAL_ACCOUNT', 'ADS_UF_DONT_EXPIRE_PASSWD']
+
+- name: get invalid property
+ win_domain_object_info:
+ filter: sAMAccountName -eq 'Ansible Test'
+ properties:
+ - FakeProperty
+ register: invalid_prop_warning
+
+- name: assert get invalid property
+ assert:
+ that:
+ - not invalid_prop_warning is changed
+ - invalid_prop_warning.objects | length == 0
+ - invalid_prop_warning.warnings | length == 1
+ - '"Failed to retrieve properties for AD object" not in invalid_prop_warning.warnings[0]'
+
+- name: get by ldap filter returning multiple
+ win_domain_object_info:
+ ldap_filter: (&(objectClass=computer)(objectCategory=computer))
+ properties: '*'
+ register: multiple_ldap
+
+- name: assert get by ldap filter returning multiple
+ assert:
+ that:
+ - not multiple_ldap is changed
+ - multiple_ldap.objects | length > 1
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_domain_ou/aliases b/ansible_collections/community/windows/tests/integration/targets/win_domain_ou/aliases
new file mode 100644
index 000000000..22f581bfd
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_domain_ou/aliases
@@ -0,0 +1,2 @@
+shippable/windows/group2
+skip/windows/2012
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_domain_ou/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_domain_ou/defaults/main.yml
new file mode 100644
index 000000000..6892b03a6
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_domain_ou/defaults/main.yml
@@ -0,0 +1,22 @@
+---
+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
+
+win_domain_ou_structure_check_mode:
+ - path: "{{ win_domain_ou_root_path }}"
+ name: VMware_check
+ - path: "OU=VMware_check,{{ win_domain_ou_root_path }}"
+ name: End User Computing
+ - path: "OU=End User Computing,OU=VMware_check,{{ win_domain_ou_root_path }}"
+ name: Workspace ONE Cloud Services
+ - path: "OU=Workspace ONE Cloud Services,OU=End User Computing,OU=VMware_check,{{ win_domain_ou_root_path }}"
+ name: SaaS Development and Enablement
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_domain_ou/meta/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_domain_ou/meta/main.yml
new file mode 100644
index 000000000..da6e52e2f
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_domain_ou/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - setup_domain_tests
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_domain_ou/tasks/check_mode_test.yml b/ansible_collections/community/windows/tests/integration/targets/win_domain_ou/tasks/check_mode_test.yml
new file mode 100644
index 000000000..730298e40
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_domain_ou/tasks/check_mode_test.yml
@@ -0,0 +1,116 @@
+---
+- name: Setup structure for checkmode
+ block:
+ - 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: test_setup_checkmode
+ failed_when: test_setup_checkmode is not changed
+
+- name: Run Check Mode Tests
+ block:
+ - name: Ensure OU is present (check_mode)
+ community.windows.win_domain_ou:
+ name: ansible_checkmode
+ register: test_check_mode_1
+ failed_when: test_check_mode_1 is not changed
+
+ - name: Ensure OU has updated properties (check_mode)
+ 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: test_check_mode_2
+ failed_when: test_check_mode_2 is not changed
+
+ - name: Ensure OU structure win_domain_ou_structure_check_mode is present (check_mode)
+ community.windows.win_domain_ou:
+ name: "{{ item.name }}"
+ protected: false
+ path: "{{ item.path }}"
+ loop: "{{ win_domain_ou_structure_check_mode }}"
+ register: test_check_mode_3
+ failed_when: test_check_mode_3 is not changed
+
+ - name: Ensure OU structure win_domain_ou_structure is present (check_mode)
+ community.windows.win_domain_ou:
+ name: "{{ item.name }}"
+ protected: false
+ path: "{{ item.path }}"
+ loop: "{{ win_domain_ou_structure }}"
+ register: test_check_mode_4
+ failed_when: test_check_mode_4 is changed
+
+ - name: Ensure OU structure is absent, recursive (check_mode)
+ community.windows.win_domain_ou:
+ name: VMware
+ path: "{{ win_domain_ou_root_path }}"
+ state: absent
+ recursive: true
+ register: test_check_mode_5
+ failed_when: test_check_mode_5 is not changed
+
+ - name: Ensure OU is present with specific properties (check_mode)
+ 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: test_check_mode_6
+ failed_when: test_check_mode_6 is not changed
+
+ - name: Ensure OU is present with specific properties added (check_mode)
+ community.windows.win_domain_ou:
+ name: VMW Atlanta
+ path: "{{ win_domain_ou_root_path }}"
+ properties:
+ country: US
+ description: EUC Business Unit
+ postalcode: 30189
+ register: test_check_mode_7
+ failed_when: test_check_mode_7 is not changed
+
+ - name: Ensure existing ou 'End User Computing' is absent (check_mode)
+ community.windows.win_domain_ou:
+ name: End User Computing
+ path: "OU=VMware,{{ win_domain_ou_root_path }}"
+ state: absent
+ register: test_check_mode_8
+ failed_when: test_check_mode_8 is not changed
+
+ - name: Ensure NonExisting OU 'VMW Atlanta' is absent (check_mode)
+ community.windows.win_domain_ou:
+ name: "VMW Atlanta"
+ path: "{{ win_domain_ou_root_path }}"
+ state: absent
+ register: test_check_mode_9
+ failed_when: test_check_mode_9 is changed
+ check_mode: true
+
+- name: sanity check on check_mode
+ ansible.windows.win_shell: |
+ get-adorganizationalunit -Identity ansible_checkmode
+ register: test_sanity
+ failed_when: "'ansible_checkmode' in test_sanity.stdout"
+ changed_when: false
+
+- name: Teardown structure used for checkmode
+ community.windows.win_domain_ou:
+ name: VMware
+ path: "{{ win_domain_ou_root_path }}"
+ state: absent
+ recursive: true
+ register: test_teardown
+ failed_when: test_teardown is not changed
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_domain_ou/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_domain_ou/tasks/main.yml
new file mode 100644
index 000000000..1ea02d5ee
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_domain_ou/tasks/main.yml
@@ -0,0 +1,6 @@
+---
+- name: Run Tests
+ import_tasks: tests.yml
+
+- name: Run Check Mode Tests
+ import_tasks: check_mode_test.yml \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_domain_ou/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_domain_ou/tasks/tests.yml
new file mode 100644
index 000000000..f5fe8d576
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_domain_ou/tasks/tests.yml
@@ -0,0 +1,190 @@
+---
+- 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 absent
+ community.windows.win_domain_ou:
+ name: AnsibleFest
+ state: absent
+ register: test1_clean
+ failed_when: test1_clean is not changed
+
+- name: Ensure OU is absent (idempotence check)
+ community.windows.win_domain_ou:
+ name: AnsibleFest
+ state: absent
+ register: test1_clean_idempotent
+ failed_when: test1_clean_idempotent 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: Assertions
+ assert:
+ that:
+ - test1a.ou.Name == "AnsibleFest"
+ - test3a.ou.StreetAddress == "1155 Perimeter Center West"
+ - test7a.ou.Country == "US"
+ - test6a.ou.City == "Sandy Springs"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_domain_user/aliases b/ansible_collections/community/windows/tests/integration/targets/win_domain_user/aliases
new file mode 100644
index 000000000..22f581bfd
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_domain_user/aliases
@@ -0,0 +1,2 @@
+shippable/windows/group2
+skip/windows/2012
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_domain_user/meta/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_domain_user/meta/main.yml
new file mode 100644
index 000000000..da6e52e2f
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_domain_user/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - setup_domain_tests
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_domain_user/tasks/check_mode_test.yml b/ansible_collections/community/windows/tests/integration/targets/win_domain_user/tasks/check_mode_test.yml
new file mode 100644
index 000000000..755135421
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_domain_user/tasks/check_mode_test.yml
@@ -0,0 +1,27 @@
+---
+- name: Create Justi (check_mode)
+ community.windows.win_domain_user:
+ name: Justi
+ password: J@n3P4ssw0rd#
+ state: present
+ update_password: on_create
+ account_locked: false
+ password_never_expires: false
+ enabled: true
+ register: new_user_check_mode
+ failed_when:
+ - not new_user_check_mode.changed
+ - not new_user_check_mode.created
+ check_mode: true
+
+- name: Sanity check on Check Mode
+ ansible.windows.win_powershell:
+ script: |
+ try {
+ Get-AdUser -Identity Justi
+ $Ansible.Failed = $true
+ } catch {
+ $Ansible.Failed = $false
+ }
+ register: sanity_check
+ changed_when: false
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_domain_user/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_domain_user/tasks/main.yml
new file mode 100644
index 000000000..2edc6ce0e
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_domain_user/tasks/main.yml
@@ -0,0 +1,18 @@
+---
+- name: Remove Users
+ win_domain_user:
+ name: "{{ item }}"
+ state: absent
+ loop:
+ - justi
+ - hana
+ - katie
+
+- name: Run Test Suite 1
+ import_tasks: test1.yml
+
+- name: Run Test Suite 2
+ import_tasks: test2.yml
+
+- name: Run Check Mode Tests
+ import_tasks: check_mode_test.yml
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_domain_user/tasks/test1.yml b/ansible_collections/community/windows/tests/integration/targets/win_domain_user/tasks/test1.yml
new file mode 100644
index 000000000..a5ba7095c
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_domain_user/tasks/test1.yml
@@ -0,0 +1,76 @@
+---
+- name: Justi | Create User
+ win_domain_user:
+ name: Justi
+ upn: justi@ansible.test
+ password: c0dinGwithKI@
+ state: present
+ update_password: on_create
+ password_never_expires: false
+ enabled: true
+ spn:
+ - MSSQLSvc/US99DBSVR1
+ - MSSQLSvc/US99DBSVR1.vmware.com
+ - MSSQLSvc/US99DBSVR1.vmware.com:1433
+ register: new_user_test
+ failed_when: new_user_test is not success
+
+- name: Justi | Create User (idempotence check)
+ win_domain_user:
+ name: Justi
+ upn: justi@ansible.test
+ password: c0dinGwithKI@
+ state: present
+ update_password: on_create
+ password_never_expires: false
+ enabled: true
+ spn:
+ - MSSQLSvc/US99DBSVR1
+ - MSSQLSvc/US99DBSVR1.vmware.com
+ - MSSQLSvc/US99DBSVR1.vmware.com:1433
+ register: new_user_test_idempotent
+ failed_when: new_user_test_idempotent is changed
+
+- name: Justi | Update Password
+ win_domain_user:
+ name: Justi
+ password: al3x@ndriastEch!
+ state: present
+ update_password: always
+ password_never_expires: false
+ enabled: true
+ register: password_changed
+ failed_when: not password_changed.changed
+
+- name: Justi | Replace SPNs
+ win_domain_user:
+ name: Justi
+ state: present
+ spn:
+ - MSSQLSvc/
+ - MSSQLSvc/US99DBSVR1.vmware.com
+ register: spn_changed
+ failed_when: not spn_changed.changed
+
+- name: Justi | Add SPN
+ win_domain_user:
+ name: Justi
+ state: present
+ spn_action: add
+ spn:
+ - MSSQLSvc/US99DBSVR1.vmware.com:2433
+ register: add_spn_changed
+ failed_when: add_spn_changed is not changed
+
+- name: Assertions
+ assert:
+ that:
+ - new_user_test.changed
+ - new_user_test.created
+ - not new_user_test.password_never_expires
+ - not new_user_test_idempotent.changed
+ - new_user_test_idempotent.distinguished_name == "CN=Justi,CN=Users,DC=ansible,DC=test"
+ - password_changed.changed
+ - password_changed.password_updated
+ - spn_changed.changed
+ - add_spn_changed.changed
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_domain_user/tasks/test2.yml b/ansible_collections/community/windows/tests/integration/targets/win_domain_user/tasks/test2.yml
new file mode 100644
index 000000000..767ed538b
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_domain_user/tasks/test2.yml
@@ -0,0 +1,171 @@
+---
+- name: Hana | Create User w/Invalid Password
+ win_domain_user:
+ name: hana
+ upn: hana@ansible.test
+ firstname: Hana
+ surname: Lytx
+ display_name: Hana Lytx
+ company: HelpMeExitVi Inc.
+ password: 123
+ state: present
+ groups:
+ - Domain Admins
+ street: 123 TechTok St.
+ city: Sysengineer
+ state_province: OH
+ postal_code: 12345
+ country: US
+ attributes:
+ telephoneNumber: 555-123456
+ update_password: when_changed
+ password_never_expires: true
+ register: bad_password_test
+ failed_when: bad_password_test is success
+
+- name: Hana | Create User Again w/Valid Password
+ win_domain_user:
+ name: hana
+ upn: hana@ansible.test
+ firstname: Hana
+ surname: Lytx
+ display_name: Hana Lytx
+ company: HelpMeExitVi Inc.
+ password: h@nAlyTx18!X
+ state: present
+ groups:
+ - Domain Admins
+ street: 123 TechTok St.
+ city: Sysengineer
+ state_province: OH
+ postal_code: 12345
+ country: US
+ attributes:
+ telephoneNumber: 555-123456
+ update_password: when_changed
+ password_never_expires: true
+ register: good_password_test
+ failed_when: good_password_test is not success
+
+- name: Katie | Create User with Delegates
+ win_domain_user:
+ name: katie
+ firstname: Katie
+ surname: Kickscancer
+ display_name: Katie Kickscancer
+ password: SyNs@tI0N
+ update_password: on_create
+ state: present
+ delegates:
+ - CN=justi,CN=Users,DC=ansible,DC=test
+ spn:
+ - HTTPSvc/judge-svc1:80
+ - HTTPSvc/gabrielle-svc1.vmware.com
+ register: delegates_test
+ failed_when: delegates_test is not success
+
+- name: Katie | Create User with Delegates (idempotence check)
+ win_domain_user:
+ name: katie
+ firstname: Katie
+ surname: Kickscancer
+ display_name: Katie Kickscancer
+ password: SyNs@tI0N
+ update_password: on_create
+ state: present
+ delegates:
+ - CN=justi,CN=Users,DC=ansible,DC=test
+ spn:
+ - HTTPSvc/judge-svc1:80
+ - HTTPSvc/gabrielle-svc1.vmware.com
+ register: delegates_test_idempotent
+ failed_when: delegates_test_idempotent is changed
+
+- name: Katie | Remove SPN
+ win_domain_user:
+ name: katie
+ state: present
+ spn_action: remove
+ spn:
+ - HTTPSvc/gabrielle-svc1.vmware.com
+ register: remove_spn_test
+ failed_when: remove_spn_test is not changed
+
+- name: Katie | Remove SPN (idempotence check)
+ win_domain_user:
+ name: katie
+ state: present
+ spn_action: remove
+ spn:
+ - HTTPSvc/gabrielle-svc1.vmware.com
+ register: remove_spn_test_idempotent
+ failed_when: remove_spn_test_idempotent is changed
+
+- name: Katie | Add to groups that are missing - fail
+ win_domain_user:
+ name: katie
+ state: present
+ groups:
+ - Missing Group
+ register: add_invalid_group_fail
+ failed_when: add_invalid_group_fail is success
+
+- name: Katie | Add to groups that are missing - warn
+ win_domain_user:
+ name: katie
+ state: present
+ groups:
+ - Missing Group
+ groups_missing_behaviour: warn
+ register: add_invalid_group_warn
+ failed_when: not add_invalid_group_warn.warnings[0].startswith("Failed to locate group Missing Group but continuing on")
+
+- name: Katie | Add to groups that are missing - ignore
+ win_domain_user:
+ name: katie
+ state: present
+ groups:
+ - Missing Group
+ groups_missing_behaviour: ignore
+ register: add_invalid_group_ignore
+ failed_when: (add_invalid_group_ignore.warnings | default([]) | length) != 0
+
+- name: Hana | Remove User
+ win_domain_user:
+ name: hana
+ state: absent
+ register: user_removed
+ failed_when: user_removed is not changed
+
+- name: Hana | Remove User (idempotence check)
+ win_domain_user:
+ name: hana
+ state: absent
+ register: user_removed_idempotent
+ failed_when: user_removed_idempotent is changed
+
+- name: Remove Justi
+ win_domain_user:
+ name: justi
+ state: absent
+
+- name: Remove Katie
+ win_domain_user:
+ name: katie
+ state: absent
+
+- name: Assertions
+ assert:
+ that:
+ - delegates_test is success
+ - not delegates_test_idempotent.changed
+ - not bad_password_test.changed
+ - good_password_test.changed
+ - good_password_test.upn == "hana@ansible.test"
+ - good_password_test.password_never_expires
+ - good_password_test.company == "HelpMeExitVi Inc."
+ - not good_password_test.created
+ - good_password_test.password_updated
+ - user_removed.state == "absent"
+ - not user_removed_idempotent.changed
+ - remove_spn_test.spn == ['HTTPSvc/judge-svc1:80']
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_dotnet_ngen/aliases b/ansible_collections/community/windows/tests/integration/targets/win_dotnet_ngen/aliases
new file mode 100644
index 000000000..3cf5b97e8
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_dotnet_ngen/aliases
@@ -0,0 +1 @@
+shippable/windows/group3
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_dotnet_ngen/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_dotnet_ngen/tasks/main.yml
new file mode 100644
index 000000000..146eeb3c5
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_dotnet_ngen/tasks/main.yml
@@ -0,0 +1,20 @@
+# this only tests check mode as the full run can take several minutes to
+# complete, this way we at least verify the script is parsable
+---
+- name: run in check mode
+ win_dotnet_ngen:
+ register: result_check
+ check_mode: yes
+
+- name: assert run in check mode
+ assert:
+ that:
+ - result_check is changed
+ - result_check.dotnet_ngen_update_exit_code == 0
+ - result_check.dotnet_ngen_update_output == "check mode output for C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\ngen.exe update /force"
+ - result_check.dotnet_ngen_eqi_exit_code == 0
+ - result_check.dotnet_ngen_eqi_output == "check mode output for C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\ngen.exe executeQueuedItems"
+ - result_check.dotnet_ngen64_update_exit_code == 0
+ - result_check.dotnet_ngen64_update_output == "check mode output for C:\\Windows\\Microsoft.NET\\Framework64\\v4.0.30319\\ngen.exe update /force"
+ - result_check.dotnet_ngen64_eqi_exit_code == 0
+ - result_check.dotnet_ngen64_eqi_output == "check mode output for C:\\Windows\\Microsoft.NET\\Framework64\\v4.0.30319\\ngen.exe executeQueuedItems"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_eventlog/aliases b/ansible_collections/community/windows/tests/integration/targets/win_eventlog/aliases
new file mode 100644
index 000000000..4f4664b68
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_eventlog/aliases
@@ -0,0 +1 @@
+shippable/windows/group5
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_eventlog/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_eventlog/tasks/main.yml
new file mode 100644
index 000000000..dcc075fcc
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_eventlog/tasks/main.yml
@@ -0,0 +1,10 @@
+- name: Run tests for win_eventlog in normal mode
+ import_tasks: tests.yml
+ vars:
+ in_check_mode: no
+
+- name: Run tests for win_eventlog in check-mode
+ import_tasks: tests.yml
+ vars:
+ in_check_mode: yes
+ check_mode: yes
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_eventlog/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_eventlog/tasks/tests.yml
new file mode 100644
index 000000000..94c231a4b
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_eventlog/tasks/tests.yml
@@ -0,0 +1,447 @@
+# Test code for win_eventlog
+
+# (c) 2017, Andrew Saraceni <andrew.saraceni@gmail.com>
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+- name: Remove potentially leftover logs
+ win_eventlog:
+ name: "{{ item }}"
+ state: absent
+ with_items:
+ - WinEventLogTest
+ - NewWinEventLogTest
+
+
+- name: Add log without sources
+ win_eventlog:
+ name: WinEventLogTest
+ state: present
+ register: add_log_without_sources
+ failed_when: add_log_without_sources.changed != false or add_log_without_sources.msg != "You must specify one or more sources when creating a log for the first time"
+
+
+- name: Add log
+ win_eventlog: &wel_present
+ name: WinEventLogTest
+ sources:
+ - WinEventLogSource1
+ - WinEventLogSource2
+ state: present
+ register: add_log
+
+- name: Test add_log (normal mode)
+ assert:
+ that:
+ - add_log.changed == true
+ - add_log.exists == true
+ - add_log.sources == ["WinEventLogSource1", "WinEventLogSource2", "WinEventLogTest"]
+ - add_log.sources_changed == ["WinEventLogSource1", "WinEventLogSource2"]
+ when: not in_check_mode
+
+- name: Test add_log (check-mode)
+ assert:
+ that:
+ - add_log.changed == true
+ - add_log.exists == false
+ - add_log.sources_changed == []
+ when: in_check_mode
+
+
+- name: Add log (again)
+ win_eventlog: *wel_present
+ register: add_log_again
+
+- name: Test add_log_again (normal mode)
+ assert:
+ that:
+ - add_log_again.changed == false
+ - add_log_again.exists == true
+ - add_log_again.sources == ["WinEventLogSource1", "WinEventLogSource2", "WinEventLogTest"]
+ - add_log_again.sources_changed == []
+ when: not in_check_mode
+
+
+- name: Run tests for normal mode only (expects event log)
+ when: not in_check_mode
+ block:
+
+ - name: Change default source
+ win_eventlog:
+ <<: *wel_present
+ sources:
+ - WinEventLogTest
+ category_file: C:\TestApp\AppCategories.dll
+ register: change_default_source
+ failed_when: change_default_source.changed != false or change_default_source.msg != "Cannot modify default source WinEventLogTest of log WinEventLogTest - you must remove the log"
+
+
+ - name: Change source category
+ win_eventlog: &welc_present
+ <<: *wel_present
+ sources:
+ - WinEventLogSource1
+ category_file: C:\TestApp\AppCategories.dll
+ register: change_source_category
+
+ - name: Test change_source_category
+ assert:
+ that:
+ - change_source_category.changed == true
+ - change_source_category.exists == true
+ - change_source_category.sources == ["WinEventLogSource1", "WinEventLogSource2", "WinEventLogTest"]
+ - change_source_category.sources_changed == ["WinEventLogSource1"]
+
+
+ - name: Change source category (again)
+ win_eventlog: *welc_present
+ register: change_source_category_again
+
+ - name: Test change_source_category_again
+ assert:
+ that:
+ - change_source_category_again.changed == false
+ - change_source_category_again.exists == true
+ - change_source_category_again.sources == ["WinEventLogSource1", "WinEventLogSource2", "WinEventLogTest"]
+ - change_source_category_again.sources_changed == []
+
+
+ - name: Change source message
+ win_eventlog: &welm_present
+ <<: *welc_present
+ message_file: C:\TestApp\AppMessages.dll
+ register: change_source_message
+
+ - name: Test change_source_message
+ assert:
+ that:
+ - change_source_message.changed == true
+ - change_source_message.exists == true
+ - change_source_message.sources == ["WinEventLogSource1", "WinEventLogSource2", "WinEventLogTest"]
+ - change_source_message.sources_changed == ["WinEventLogSource1"]
+
+
+ - name: Change source message (again)
+ win_eventlog: *welm_present
+ register: change_source_message_again
+
+ - name: Test change_source_message_again
+ assert:
+ that:
+ - change_source_message_again.changed == false
+ - change_source_message_again.exists == true
+ - change_source_message_again.sources == ["WinEventLogSource1", "WinEventLogSource2", "WinEventLogTest"]
+ - change_source_message_again.sources_changed == []
+
+
+ - name: Change source parameter
+ win_eventlog: &welp_present
+ <<: *welm_present
+ parameter_file: C:\TestApp\AppParameters.dll
+ register: change_source_parameter
+
+ - name: Test change_source_parameter
+ assert:
+ that:
+ - change_source_parameter.changed == true
+ - change_source_parameter.exists == true
+ - change_source_parameter.sources == ["WinEventLogSource1", "WinEventLogSource2", "WinEventLogTest"]
+ - change_source_parameter.sources_changed == ["WinEventLogSource1"]
+
+
+ - name: Change source parameter (again)
+ win_eventlog: *welp_present
+ register: change_source_parameter_again
+
+ - name: Test change_source_parameter_again
+ assert:
+ that:
+ - change_source_parameter_again.changed == false
+ - change_source_parameter_again.exists == true
+ - change_source_parameter_again.sources == ["WinEventLogSource1", "WinEventLogSource2", "WinEventLogTest"]
+ - change_source_parameter_again.sources_changed == []
+
+
+ - name: Change log maximum size
+ win_eventlog: &wels_present
+ <<: *wel_present
+ maximum_size: 256MB
+ register: change_log_maximum_size
+
+ - name: Test change_log_maximum_size
+ assert:
+ that:
+ - change_log_maximum_size.changed == true
+ - change_log_maximum_size.exists == true
+ - change_log_maximum_size.maximum_size_kb == 262144
+
+
+ - name: Change log maximum size (again)
+ win_eventlog: *wels_present
+ register: change_log_maximum_size_again
+
+ - name: Test change_log_maximum_size_again
+ assert:
+ that:
+ - change_log_maximum_size_again.changed == false
+ - change_log_maximum_size_again.exists == true
+ - change_log_maximum_size_again.maximum_size_kb == 262144
+
+
+ - name: Change log invalid maximum size 1
+ win_eventlog:
+ <<: *wel_present
+ maximum_size: 256 MB
+ register: change_log_invalid_maximum_size_1
+ failed_when: change_log_invalid_maximum_size_1.changed != false or change_log_invalid_maximum_size_1.msg != "Maximum size 256 MB is not properly specified"
+
+
+ - name: Change log invalid maximum size 2
+ win_eventlog:
+ <<: *wel_present
+ maximum_size: 5GB
+ register: change_log_invalid_maximum_size_2
+ failed_when: change_log_invalid_maximum_size_2.changed != false or change_log_invalid_maximum_size_2.msg != "Maximum size must be between 64KB and 4GB"
+
+
+ - name: Change log invalid maximum size 3
+ win_eventlog:
+ <<: *wel_present
+ maximum_size: 129KB
+ register: change_log_invalid_maximum_size_3
+ failed_when: change_log_invalid_maximum_size_3.changed != false or change_log_invalid_maximum_size_3.msg != "Maximum size must be divisible by 64KB"
+
+
+ - name: Change log retention days
+ win_eventlog: &welr_present
+ <<: *wels_present
+ retention_days: 128
+ register: change_log_retention_days
+
+ - name: Test change_log_retention_days
+ assert:
+ that:
+ - change_log_retention_days.changed == true
+ - change_log_retention_days.exists == true
+ - change_log_retention_days.retention_days == 128
+
+
+ - name: Change log retention days (again)
+ win_eventlog: *welr_present
+ register: change_log_retention_days_again
+
+ - name: Test change_log_retention_days_again
+ assert:
+ that:
+ - change_log_retention_days_again.changed == false
+ - change_log_retention_days_again.exists == true
+ - change_log_retention_days_again.retention_days == 128
+
+
+ - name: Change log overflow action
+ win_eventlog: &welo_present
+ <<: *wels_present
+ overflow_action: OverwriteAsNeeded
+ register: change_log_overflow_action
+
+ - name: Test change_log_overflow_action
+ assert:
+ that:
+ - change_log_overflow_action.changed == true
+ - change_log_overflow_action.exists == true
+ - change_log_overflow_action.overflow_action == "OverwriteAsNeeded"
+
+
+ - name: Change log overflow action (again)
+ win_eventlog: *welo_present
+ register: change_log_overflow_action_again
+
+ - name: Test change_log_overflow_action_again
+ assert:
+ that:
+ - change_log_overflow_action_again.changed == false
+ - change_log_overflow_action_again.exists == true
+ - change_log_overflow_action_again.overflow_action == "OverwriteAsNeeded"
+
+
+ - name: Add log with existing source
+ win_eventlog: &wele_present
+ name: NewWinEventLogTest
+ sources:
+ - WinEventLogSource1
+ state: present
+ register: add_log_with_existing_source
+ failed_when: add_log_with_existing_source.changed != false or add_log_with_existing_source.msg != "Source WinEventLogSource1 already exists and cannot be created"
+
+
+ - name: Add new log
+ win_eventlog:
+ <<: *wele_present
+ sources:
+ - NewWinEventLogSource1
+
+ - name: Change source for different log
+ win_eventlog:
+ <<: *wele_present
+ sources:
+ - WinEventLogSource1
+ category_file: C:\TestApp\AppCategories.dll
+ register: change_source_for_different_log
+ failed_when: change_source_for_different_log.changed != false or change_source_for_different_log.msg != "Source WinEventLogSource1 does not belong to log NewWinEventLogTest and cannot be modified"
+
+ - name: Remove new log
+ win_eventlog:
+ name: NewWinEventLogTest
+ state: absent
+
+
+ - name: Add entry to log
+ ansible.windows.win_shell: Write-EventLog -LogName WinEventLogTest -Source WinEventLogSource1 -EntryType Information -EventId 12345 -Message "Test message"
+
+ - name: Verify add entry
+ win_eventlog:
+ name: WinEventLogTest
+ state: present
+ register: verify_add_entry
+
+ - name: Test verify_add_entry
+ assert:
+ that:
+ - verify_add_entry.changed == false
+ - verify_add_entry.exists == true
+ - verify_add_entry.entries == 1
+
+
+ - name: Clear log
+ win_eventlog: &wel_clear
+ name: WinEventLogTest
+ state: clear
+ register: clear_log
+
+ - name: Test clear_log
+ assert:
+ that:
+ - clear_log.changed == true
+ - clear_log.exists == true
+ - clear_log.entries == 0
+ when: not in_check_mode
+
+
+ - name: Clear log (again)
+ win_eventlog: *wel_clear
+ register: clear_log_again
+
+ - name: Test clear_log_again
+ assert:
+ that:
+ - clear_log_again.changed == false
+ - clear_log_again.exists == true
+ - clear_log_again.entries == 0
+ when: in_check_mode
+
+
+- name: Clear absent log
+ win_eventlog:
+ name: WinEventLogTest
+ state: clear
+ register: clear_absent_log
+ when: in_check_mode
+ failed_when: clear_absent_log.changed != false or clear_absent_log.msg != "Cannot clear log WinEventLogTest as it does not exist"
+
+
+- name: Remove default source
+ win_eventlog: &weld_absent
+ name: WinEventLogTest
+ sources:
+ - WinEventLogTest
+ state: absent
+ register: remove_default_source
+ failed_when: remove_default_source.changed != false or remove_default_source.msg != "Cannot remove default source WinEventLogTest from log WinEventLogTest - you must remove the log"
+
+
+- name: Remove source
+ win_eventlog: &wels_absent
+ <<: *weld_absent
+ sources:
+ - WinEventLogSource1
+ register: remove_source
+
+- name: Test remove_source (normal mode)
+ assert:
+ that:
+ - remove_source.changed == true
+ - remove_source.exists == true
+ - remove_source.sources == ["WinEventLogSource2", "WinEventLogTest"]
+ - remove_source.sources_changed == ["WinEventLogSource1"]
+ when: not in_check_mode
+
+- name: Test remove_source (check-mode)
+ assert:
+ that:
+ - remove_source.changed == false
+ - remove_source.exists == false
+ - remove_source.sources_changed == []
+ when: in_check_mode
+
+
+- name: Remove source (again)
+ win_eventlog: *wels_absent
+ register: remove_source_again
+
+- name: Test remove_source_again (normal mode)
+ assert:
+ that:
+ - remove_source_again.changed == false
+ - remove_source_again.exists == true
+ - remove_source.sources == ["WinEventLogSource2", "WinEventLogTest"]
+ - remove_source_again.sources_changed == []
+ when: not in_check_mode
+
+
+- name: Remove log
+ win_eventlog: &wel_absent
+ name: WinEventLogTest
+ state: absent
+ register: remove_log
+
+- name: Test remove_log (normal mode)
+ assert:
+ that:
+ - remove_log.changed == true
+ - remove_log.exists == false
+ - remove_log.sources_changed == ["WinEventLogSource2", "WinEventLogTest"]
+ when: not in_check_mode
+
+- name: Test remove_log (check-mode)
+ assert:
+ that:
+ - remove_log.changed == false
+ - remove_log.exists == false
+ - remove_log.sources_changed == []
+ when: in_check_mode
+
+
+- name: Remove log (again)
+ win_eventlog: *wel_absent
+ register: remove_log_again
+
+- name: Test remove_log_again (normal mode)
+ assert:
+ that:
+ - remove_log_again.changed == false
+ - remove_log_again.exists == false
+ - remove_log_again.sources_changed == []
+ when: not in_check_mode
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_eventlog_entry/aliases b/ansible_collections/community/windows/tests/integration/targets/win_eventlog_entry/aliases
new file mode 100644
index 000000000..215e0b069
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_eventlog_entry/aliases
@@ -0,0 +1 @@
+shippable/windows/group4
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_eventlog_entry/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_eventlog_entry/defaults/main.yml
new file mode 100644
index 000000000..611d16ec0
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_eventlog_entry/defaults/main.yml
@@ -0,0 +1,6 @@
+win_test_log_source:
+ log: WinEventLogEntryTest
+ source: WinEventLogEntrySource
+win_test_log_source_extra:
+ log: ExtraWinEventLogEntryTest
+ source: ExtraWinEventLogEntrySource
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_eventlog_entry/library/test_win_eventlog_entry.ps1 b/ansible_collections/community/windows/tests/integration/targets/win_eventlog_entry/library/test_win_eventlog_entry.ps1
new file mode 100644
index 000000000..2af179b5f
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_eventlog_entry/library/test_win_eventlog_entry.ps1
@@ -0,0 +1,33 @@
+#!powershell
+
+# (c) 2017, Andrew Saraceni <andrew.saraceni@gmail.com>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#Requires -Module Ansible.ModuleUtils.Legacy
+
+# Test module used to grab the latest entry from an event log and output its properties
+
+$ErrorActionPreference = "Stop"
+
+$params = Parse-Args $args -supports_check_mode $true
+$log = Get-AnsibleParam -obj $params -name "log" -type "str" -failifempty $true
+
+$result = @{
+ changed = $false
+}
+
+try {
+ $log_entry = Get-EventLog -LogName $log | Select-Object -First 1 -Property *
+}
+catch {
+ Fail-Json -obj $result -message "Could not find any entries for log $log"
+}
+
+$result.source = $log_entry.Source
+$result.event_id = $log_entry.EventID
+$result.message = $log_entry.Message
+$result.entry_type = $log_entry.EntryType.ToString()
+$result.category = $log_entry.CategoryNumber
+$result.raw_data = $log_entry.Data -join ","
+
+Exit-Json -obj $result
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_eventlog_entry/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_eventlog_entry/tasks/main.yml
new file mode 100644
index 000000000..9f416598e
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_eventlog_entry/tasks/main.yml
@@ -0,0 +1,33 @@
+# win_shell invocations can eventually be replaced with win_eventlog
+- name: Remove potentially leftover test logs and sources
+ ansible.windows.win_shell: Remove-EventLog -LogName "{{ item.log }}" -ErrorAction SilentlyContinue
+ with_items:
+ - "{{ win_test_log_source }}"
+ - "{{ win_test_log_source_extra }}"
+ failed_when: no
+
+- name: Add new test logs and sources
+ ansible.windows.win_shell: New-EventLog -LogName "{{ item.log }}" -Source "{{ item.source }}"
+ with_items:
+ - "{{ win_test_log_source }}"
+ - "{{ win_test_log_source_extra }}"
+
+- name: Run tests for win_eventlog_entry
+ block:
+
+ - name: Test in normal mode
+ import_tasks: tests.yml
+ vars:
+ in_check_mode: no
+
+ - name: Test in check-mode
+ import_tasks: tests.yml
+ vars:
+ in_check_mode: yes
+ check_mode: yes
+
+- name: Remove test logs and sources
+ ansible.windows.win_shell: Remove-EventLog -LogName "{{ item.log }}"
+ with_items:
+ - "{{ win_test_log_source }}"
+ - "{{ win_test_log_source_extra }}"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_eventlog_entry/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_eventlog_entry/tasks/tests.yml
new file mode 100644
index 000000000..688a4b532
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_eventlog_entry/tasks/tests.yml
@@ -0,0 +1,159 @@
+# Test code for win_eventlog_entry
+
+# (c) 2017, Andrew Saraceni <andrew.saraceni@gmail.com>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+- name: Add entry to fake log
+ win_eventlog_entry:
+ log: FakeLogName
+ source: "{{ win_test_log_source.source }}"
+ event_id: 12345
+ message: This is a test log entry message
+ register: add_entry_to_fake_log
+ failed_when: add_entry_to_fake_log.changed != false or add_entry_to_fake_log.msg != "Log FakeLogName does not exist and cannot be written to"
+
+
+- name: Add entry from fake source
+ win_eventlog_entry:
+ log: "{{ win_test_log_source.log }}"
+ source: FakeSourceName
+ event_id: 12345
+ message: This is a test log entry message
+ register: add_entry_from_fake_source
+ failed_when: add_entry_from_fake_source.changed != false or add_entry_from_fake_source.msg != "Source FakeSourceName does not exist"
+
+
+- name: Add entry with invalid event_id
+ win_eventlog_entry:
+ log: "{{ win_test_log_source.log }}"
+ source: "{{ win_test_log_source.source }}"
+ event_id: 67000
+ message: This is a test log entry message
+ register: add_entry_with_invalid_event_id
+ failed_when: add_entry_with_invalid_event_id.changed != false or add_entry_with_invalid_event_id.msg != "Event ID must be between 0 and 65535"
+
+
+- name: Add entry from other log source
+ win_eventlog_entry:
+ log: "{{ win_test_log_source.log }}"
+ source: "{{ win_test_log_source_extra.source }}"
+ event_id: 12345
+ message: This is a test log entry message
+ register: add_entry_from_other_log_source
+ failed_when: add_entry_from_other_log_source.changed != false or add_entry_from_other_log_source.msg != "Source {{ win_test_log_source_extra.source }} does not belong to log {{ win_test_log_source.log }} and cannot be written to"
+
+
+- name: Add entry
+ win_eventlog_entry: &wele
+ log: "{{ win_test_log_source.log }}"
+ source: "{{ win_test_log_source.source }}"
+ event_id: 12345
+ message: This is a test log entry message
+ register: add_entry
+
+- name: Test add_entry
+ assert:
+ that:
+ - add_entry.changed == true
+ - add_entry.msg == "Entry added to log {{ win_test_log_source.log }} from source {{ win_test_log_source.source }}"
+
+- name: Test add_entry count (normal mode)
+ ansible.windows.win_shell: (Get-EventLog -LogName "{{ win_test_log_source.log }}").Count
+ register: add_entry_count
+ failed_when: add_entry_count.stdout_lines[0] != "1"
+ when: not in_check_mode
+
+- name: Test add_entry result (normal mode)
+ test_win_eventlog_entry:
+ log: "{{ win_test_log_source.log }}"
+ register: add_entry_result
+ when: not in_check_mode
+
+- name: Test add_entry_result (normal mode)
+ assert:
+ that:
+ - add_entry_result.source == win_test_log_source.source
+ - add_entry_result.event_id == 12345
+ - add_entry_result.message == "This is a test log entry message"
+ when: not in_check_mode
+
+
+- name: Add entry (again)
+ win_eventlog_entry: *wele
+ register: add_entry_again
+
+- name: Test add_entry_again (normal mode)
+ assert:
+ that:
+ - add_entry_again.changed == true
+ - add_entry_again.msg == "Entry added to log {{ win_test_log_source.log }} from source {{ win_test_log_source.source }}"
+ when: not in_check_mode
+
+- name: Test add_entry_again count (normal mode)
+ ansible.windows.win_shell: (Get-EventLog -LogName "{{ win_test_log_source.log }}").Count
+ register: add_entry_again_count
+ failed_when: add_entry_again_count.stdout_lines[0] != "2"
+ when: not in_check_mode
+
+
+- name: Add entry all options
+ win_eventlog_entry: &wele_ao
+ <<: *wele
+ event_id: 500
+ message: This is a test error message
+ entry_type: Error
+ category: 5
+ raw_data: 10,20
+ register: add_entry_all_options
+
+- name: Test add_entry_all_options
+ assert:
+ that:
+ - add_entry_all_options.changed == true
+ - add_entry_all_options.msg == "Entry added to log {{ win_test_log_source.log }} from source {{ win_test_log_source.source }}"
+
+- name: Test add_entry_all_options count (normal mode)
+ ansible.windows.win_shell: (Get-EventLog -LogName "{{ win_test_log_source.log }}").Count
+ register: add_entry_all_options_count
+ failed_when: add_entry_all_options_count.stdout_lines[0] != "3"
+ when: not in_check_mode
+
+- name: Test add_entry_all_options result (normal mode)
+ test_win_eventlog_entry:
+ log: "{{ win_test_log_source.log }}"
+ register: add_entry_all_options_result
+ when: not in_check_mode
+
+- name: Test add_entry_all_options_result (normal mode)
+ assert:
+ that:
+ - add_entry_all_options_result.source == win_test_log_source.source
+ - add_entry_all_options_result.event_id == 500
+ - add_entry_all_options_result.message == "This is a test error message"
+ - add_entry_all_options_result.entry_type == "Error"
+ - add_entry_all_options_result.category == 5
+ - add_entry_all_options_result.raw_data == "10,20"
+ when: not in_check_mode
+
+
+- name: Add entry all options (again)
+ win_eventlog_entry: *wele_ao
+ register: add_entry_all_options_again
+
+- name: Test add_entry_all_options_again (normal mode)
+ assert:
+ that:
+ - add_entry_all_options_again.changed == true
+ - add_entry_all_options_again.msg == "Entry added to log {{ win_test_log_source.log }} from source {{ win_test_log_source.source }}"
+ when: not in_check_mode
+
+- name: Test add_entry_all_options_again count (normal mode)
+ ansible.windows.win_shell: (Get-EventLog -LogName "{{ win_test_log_source.log }}").Count
+ register: add_entry_all_options_again_count
+ failed_when: add_entry_all_options_again_count.stdout_lines[0] != "4"
+ when: not in_check_mode
+
+
+- name: Clear event log entries
+ ansible.windows.win_shell: Clear-EventLog -LogName "{{ win_test_log_source.log }}"
+ when: not in_check_mode
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_feature_info/aliases b/ansible_collections/community/windows/tests/integration/targets/win_feature_info/aliases
new file mode 100644
index 000000000..215e0b069
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_feature_info/aliases
@@ -0,0 +1 @@
+shippable/windows/group4
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_feature_info/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_feature_info/defaults/main.yml
new file mode 100644
index 000000000..01cc5ee55
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_feature_info/defaults/main.yml
@@ -0,0 +1,2 @@
+---
+test_feature: Telnet-Client
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_feature_info/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_feature_info/tasks/main.yml
new file mode 100644
index 000000000..a6fdb28f6
--- /dev/null
+++ b/ansible_collections/community/windows/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_present
+
+- name: assert test info on single feature
+ assert:
+ that:
+ - 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:
+ name: "{{ test_feature }}"
+ state: absent
+
+- name: test info on a single Feature
+ win_feature_info:
+ name: '{{ test_feature }}'
+ register: specific_feature_absent
+
+- name: assert test info on single feature
+ assert:
+ that:
+ - not specific_feature_absent is changed
+ - specific_feature_absent.exists
+ - specific_feature_absent.features | length == 1
+ - specific_feature_absent.features[0].install_state == "Available"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_file_compression/aliases b/ansible_collections/community/windows/tests/integration/targets/win_file_compression/aliases
new file mode 100644
index 000000000..215e0b069
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_file_compression/aliases
@@ -0,0 +1 @@
+shippable/windows/group4
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_file_compression/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_file_compression/defaults/main.yml
new file mode 100644
index 000000000..ae24afe7c
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_file_compression/defaults/main.yml
@@ -0,0 +1,5 @@
+test_win_file_compression_suffix: win_file_compression .ÅÑŚÌβŁÈ [$!@^&test(;)]
+test_win_file_compression_sub_directories:
+ - 'a'
+ - 'b'
+test_win_file_compression_filename: 'foo.bar'
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_file_compression/meta/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_file_compression/meta/main.yml
new file mode 100644
index 000000000..9f37e96cd
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_file_compression/meta/main.yml
@@ -0,0 +1,2 @@
+dependencies:
+- setup_remote_tmp_dir
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_file_compression/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_file_compression/tasks/main.yml
new file mode 100644
index 000000000..542728bd7
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_file_compression/tasks/main.yml
@@ -0,0 +1,224 @@
+---
+- name: set fact of special testing dir
+ set_fact:
+ test_directory: '{{ remote_tmp_dir }}\{{ test_win_file_compression_suffix }}'
+
+- name: create sub directories
+ ansible.windows.win_file:
+ state: directory
+ path: "{{ test_directory }}\\{{ item }}"
+ loop: "{{ test_win_file_compression_sub_directories }}"
+
+- name: set main directory as hidden to test out edge cases
+ ansible.windows.win_shell: (Get-Item -LiteralPath '{{ test_directory }}').Attributes = [System.IO.FileAttributes]::Hidden
+
+- name: Compress parent directory
+ win_file_compression:
+ path: "{{ test_directory }}"
+ state: present
+ register: result
+
+- name: Get actual attributes for parent directory
+ ansible.windows.win_stat:
+ path: "{{ test_directory }}"
+ register: folder_info
+
+- assert:
+ that:
+ - "'Compressed' in folder_info.stat.attributes"
+ - "result.changed == true"
+
+- name: Get actual attributes for sub directories
+ ansible.windows.win_stat:
+ path: "{{ test_directory }}\\{{ item }}"
+ register: subfolder_info
+ loop: "{{ test_win_file_compression_sub_directories }}"
+
+- assert:
+ that:
+ - "'Compressed' not in item.stat.attributes"
+ loop: "{{ subfolder_info.results }}"
+
+- name: Compress parent directory (idempotent)
+ win_file_compression:
+ path: "{{ test_directory }}"
+ state: present
+ register: result
+
+- assert:
+ that:
+ - "result.changed == false"
+
+- name: Compress parent directory and all subdirectories
+ win_file_compression:
+ path: "{{ test_directory }}"
+ state: present
+ recurse: yes
+ register: result
+
+- name: Get actual attributes for parent directory
+ ansible.windows.win_stat:
+ path: "{{ test_directory }}"
+ register: folder_info
+
+- assert:
+ that:
+ - "'Compressed' in folder_info.stat.attributes"
+ - "result.changed == true"
+
+- name: Get actual attributes for sub directories
+ ansible.windows.win_stat:
+ path: "{{ test_directory }}\\{{ item }}"
+ register: subfolder_info
+ loop: "{{ test_win_file_compression_sub_directories }}"
+
+- assert:
+ that:
+ - "'Compressed' in item.stat.attributes"
+ loop: "{{ subfolder_info.results }}"
+
+- name: Compress parent directory and all subdirectories (idempotent)
+ win_file_compression:
+ path: "{{ test_directory }}"
+ state: present
+ recurse: yes
+ register: result
+
+- assert:
+ that:
+ - "result.changed == false"
+
+- name: Uncompress parent directory
+ win_file_compression:
+ path: "{{ test_directory }}"
+ state: absent
+ recurse: no
+ register: result
+
+- name: Get actual attributes for parent directory
+ ansible.windows.win_stat:
+ path: "{{ test_directory }}"
+ register: folder_info
+
+- assert:
+ that:
+ - "'Compressed' not in folder_info.stat.attributes"
+ - "result.changed == true"
+
+- name: Get actual attributes for sub directories
+ ansible.windows.win_stat:
+ path: "{{ test_directory }}\\{{ item }}"
+ register: subfolder_info
+ loop: "{{ test_win_file_compression_sub_directories }}"
+
+- assert:
+ that:
+ - "'Compressed' in item.stat.attributes"
+ loop: "{{ subfolder_info.results }}"
+
+- name: Uncompress parent directory (idempotent)
+ win_file_compression:
+ path: "{{ test_directory }}"
+ state: absent
+ recurse: no
+ register: result
+
+- assert:
+ that:
+ - "result.changed == false"
+
+- name: Uncompress parent directory and all subdirectories
+ win_file_compression:
+ path: "{{ test_directory }}"
+ state: absent
+ recurse: yes
+ register: result
+
+- name: Get actual attributes for parent directory
+ ansible.windows.win_stat:
+ path: "{{ test_directory }}"
+ register: folder_info
+
+- assert:
+ that:
+ - "'Compressed' not in folder_info.stat.attributes"
+ - "result.changed == true"
+
+- name: Get actual attributes for sub directories
+ ansible.windows.win_stat:
+ path: "{{ test_directory }}\\{{ item }}"
+ register: subfolder_info
+ loop: "{{ test_win_file_compression_sub_directories }}"
+
+- assert:
+ that:
+ - "'Compressed' not in item.stat.attributes"
+ loop: "{{ subfolder_info.results }}"
+
+- name: Uncompress parent directory and all subdirectories (idempotent)
+ win_file_compression:
+ path: "{{ test_directory }}"
+ state: absent
+ recurse: yes
+ register: result
+
+- assert:
+ that:
+ - "result.changed == false"
+
+- name: Create test file
+ ansible.windows.win_file:
+ state: touch
+ path: "{{ test_directory }}\\{{ test_win_file_compression_filename }}"
+
+- name: Compress specific file
+ win_file_compression:
+ path: "{{ test_directory }}\\{{ test_win_file_compression_filename }}"
+ state: present
+ register: result
+
+- name: Get actual attributes of file
+ ansible.windows.win_stat:
+ path: "{{ test_directory }}\\{{ test_win_file_compression_filename }}"
+ register: testfile_info
+
+- assert:
+ that:
+ - "result.changed == true"
+ - "'Compressed' in testfile_info.stat.attributes"
+
+- name: Compress specific file (idempotent)
+ win_file_compression:
+ path: "{{ test_directory }}\\{{ test_win_file_compression_filename }}"
+ state: present
+ register: result
+
+- assert:
+ that:
+ - "result.changed == false"
+
+- name: Uncompress specific file
+ win_file_compression:
+ path: "{{ test_directory }}\\{{ test_win_file_compression_filename }}"
+ state: absent
+ register: result
+
+- name: Get actual attributes of file
+ ansible.windows.win_stat:
+ path: "{{ test_directory }}\\{{ test_win_file_compression_filename }}"
+ register: testfile_info
+
+- assert:
+ that:
+ - "result.changed == true"
+ - "'Compressed' not in testfile_info.stat.attributes"
+
+- name: Uncompress specific file (idempotent)
+ win_file_compression:
+ path: "{{ test_directory }}\\{{ test_win_file_compression_filename }}"
+ state: absent
+ register: result
+
+- assert:
+ that:
+ - "result.changed == false"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_firewall/aliases b/ansible_collections/community/windows/tests/integration/targets/win_firewall/aliases
new file mode 100644
index 000000000..c8fd90a1f
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_firewall/aliases
@@ -0,0 +1,3 @@
+shippable/windows/group5
+skip/windows/2012
+skip/windows/2012-R2
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_firewall/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_firewall/tasks/main.yml
new file mode 100644
index 000000000..d1e4d89c4
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_firewall/tasks/main.yml
@@ -0,0 +1,52 @@
+# NOTE: The win_firewall module only works on WMF 5+
+
+- ansible.windows.setup:
+
+- name: Test Windows capabilities
+ raw: Get-Command Get-NetFirewallProfile -ErrorAction SilentlyContinue; return $?
+ failed_when: no
+ register: get_netfirewallprofile
+
+- name: Only run tests when Windows is capable
+ when: get_netfirewallprofile.rc == 0 and ansible_powershell_version >= 5
+ block:
+ - name: Turn off Windows Firewall (begin)
+ win_firewall:
+ profiles: [ Domain, Private, Public ]
+ state: disabled
+ register: firewall_off
+
+ - name: Test firewall_off
+ assert:
+ that:
+ - not firewall_off.Domain.enabled
+ - not firewall_off.Private.enabled
+ - not firewall_off.Public.enabled
+
+
+ - name: Test in normal mode
+ import_tasks: tests.yml
+ vars:
+ in_check_mode: no
+
+
+ - name: Test in check-mode
+ import_tasks: tests.yml
+ vars:
+ in_check_mode: yes
+ check_mode: yes
+
+
+ - name: Turn on Windows Firewall (end)
+ win_firewall:
+ profiles: [ Domain, Private, Public ]
+ state: enabled
+ register: firewall_on
+
+ - name: Test firewall_on
+ assert:
+ that:
+ - firewall_on is changed
+ - firewall_on.Domain.enabled
+ - firewall_on.Private.enabled
+ - firewall_on.Public.enabled
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_firewall/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_firewall/tasks/tests.yml
new file mode 100644
index 000000000..80b5f1553
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_firewall/tasks/tests.yml
@@ -0,0 +1,268 @@
+# We start with firewall turned off
+
+- name: Turn off Windows Firewall again
+ win_firewall:
+ profiles: [ Domain, Private, Public ]
+ state: disabled
+ register: firewall_off_again
+
+- name: Test firewall_off_again
+ assert:
+ that:
+ - firewall_off_again is not changed
+ - not firewall_off_again.Domain.enabled
+ - not firewall_off_again.Private.enabled
+ - not firewall_off_again.Public.enabled
+
+- name: Turn on Windows Firewall on Public
+ win_firewall:
+ profiles: [ Public ]
+ state: enabled
+ register: firewall_public_on
+
+- name: Test firewall_public_on
+ assert:
+ that:
+ - firewall_public_on is changed
+ - not firewall_public_on.Domain.enabled
+ - not firewall_public_on.Private.enabled
+ - firewall_public_on.Public.enabled
+
+
+- name: Turn on Windows Firewall on Public again
+ win_firewall:
+ profiles: [ Public ]
+ state: enabled
+ register: firewall_public_on_again
+
+- name: Test firewall_public_on_again (normal mode)
+ assert:
+ that:
+ - firewall_public_on_again is not changed
+ - not firewall_public_on_again.Domain.enabled
+ - not firewall_public_on_again.Private.enabled
+ - firewall_public_on_again.Public.enabled
+ when: not in_check_mode
+
+- name: Test firewall_public_on_again (check-mode)
+ assert:
+ that:
+ - firewall_public_on_again is changed
+ - not firewall_public_on_again.Domain.enabled
+ - not firewall_public_on_again.Private.enabled
+ - firewall_public_on_again.Public.enabled
+ when: in_check_mode
+
+
+# On purpose not a list
+- name: Turn on Windows Firewall on Domain
+ win_firewall:
+ profiles: Domain
+ state: enabled
+ register: firewall_domain_on
+
+- name: Test firewall_domain_on (normal mode)
+ assert:
+ that:
+ - firewall_domain_on is changed
+ - firewall_domain_on.Domain.enabled
+ - not firewall_domain_on.Private.enabled
+ - firewall_domain_on.Public.enabled
+ when: not in_check_mode
+
+- name: Test firewall_domain_on (check-mode)
+ assert:
+ that:
+ - firewall_domain_on is changed
+ - firewall_domain_on.Domain.enabled
+ - not firewall_domain_on.Private.enabled
+ - not firewall_domain_on.Public.enabled
+ when: in_check_mode
+
+
+- name: Turn on Windows Firewall on Domain again
+ win_firewall:
+ profiles: [ Domain ]
+ state: enabled
+ register: firewall_domain_on_again
+
+- name: Test firewall_domain_on_again (normal mode)
+ assert:
+ that:
+ - firewall_domain_on_again is not changed
+ - firewall_domain_on.Domain.enabled
+ - not firewall_domain_on.Private.enabled
+ - firewall_domain_on.Public.enabled
+ when: not in_check_mode
+
+- name: Test firewall_domain_on_again (check-mode)
+ assert:
+ that:
+ - firewall_domain_on_again is changed
+ - firewall_domain_on.Domain.enabled
+ - not firewall_domain_on.Private.enabled
+ - not firewall_domain_on.Public.enabled
+ when: in_check_mode
+
+
+- name: Turn on Windows Firewall
+ win_firewall:
+ profiles: [ Domain, Private, Public ]
+ state: enabled
+ register: firewall_on
+
+- name: Test firewall_on
+ assert:
+ that:
+ - firewall_on is changed
+ - firewall_on.Domain.enabled
+ - firewall_on.Private.enabled
+ - firewall_on.Public.enabled
+
+- name: Turn on Windows Firewall on Domain with allow inbound connection
+ win_firewall:
+ profiles: Domain
+ state: enabled
+ inbound_action: allow
+ register: firewall_domain_on
+
+- name: Test firewall_domain_on (normal mode)
+ assert:
+ that:
+ - firewall_domain_on is changed
+ - firewall_domain_on.Domain.enabled
+ when: not in_check_mode
+
+- name: Test firewall_domain_on (check-mode)
+ assert:
+ that:
+ - firewall_domain_on is changed
+ - firewall_domain_on.Domain.enabled
+ when: in_check_mode
+
+- name: Turn on Windows Firewall on Domain again with allow inbound
+ win_firewall:
+ profiles: [ Domain ]
+ state: enabled
+ inbound_action: allow
+ register: firewall_domain_on_again
+
+- name: Test firewall_domain_on_again (normal mode)
+ assert:
+ that:
+ - firewall_domain_on_again is not changed
+ - firewall_domain_on.Domain.enabled
+ when: not in_check_mode
+
+- name: Test firewall_domain_on_again (check-mode)
+ assert:
+ that:
+ - firewall_domain_on_again is changed
+ - firewall_domain_on.Domain.enabled
+ when: in_check_mode
+
+- name: Turn on Windows Firewall on Domain with block outbound connection
+ win_firewall:
+ profiles: Domain
+ state: enabled
+ outbound_action: block
+ register: firewall_domain_on
+
+- name: Test firewall_domain_on (normal mode)
+ assert:
+ that:
+ - firewall_domain_on is changed
+ - firewall_domain_on.Domain.enabled
+ when: not in_check_mode
+
+- name: Test firewall_domain_on (check-mode)
+ assert:
+ that:
+ - firewall_domain_on is changed
+ - firewall_domain_on.Domain.enabled
+ when: in_check_mode
+
+- name: Turn on Windows Firewall on Domain again with block outbound connection
+ win_firewall:
+ profiles: [ Domain ]
+ state: enabled
+ outbound_action: block
+ register: firewall_domain_on_again
+
+- name: Test firewall_domain_on_again (normal mode)
+ assert:
+ that:
+ - firewall_domain_on_again is not changed
+ - firewall_domain_on.Domain.enabled
+ when: not in_check_mode
+
+- name: Test firewall_domain_on_again (check-mode)
+ assert:
+ that:
+ - firewall_domain_on_again is changed
+ - firewall_domain_on.Domain.enabled
+ when: in_check_mode
+
+# On purpose no profiles added
+- name: Turn on Windows Firewall again
+ win_firewall:
+ state: enabled
+ register: firewall_on_again
+
+- name: Test firewall_on_again (normal mode)
+ assert:
+ that:
+ - firewall_on_again is not changed
+ - firewall_on_again.Domain.enabled
+ - firewall_on_again.Private.enabled
+ - firewall_on_again.Public.enabled
+ when: not in_check_mode
+
+- name: Test firewall_on_again (check-mode)
+ assert:
+ that:
+ - firewall_on_again is changed
+ - firewall_on_again.Domain.enabled
+ - firewall_on_again.Private.enabled
+ - firewall_on_again.Public.enabled
+ when: in_check_mode
+
+
+# On purpose no profiles added
+- name: Turn off Windows Firewall
+ win_firewall:
+ state: disabled
+ register: firewall_off2
+
+- name: Test firewall_off2 (normal mode)
+ assert:
+ that:
+ - firewall_off2 is changed
+ - not firewall_off2.Domain.enabled
+ - not firewall_off2.Private.enabled
+ - not firewall_off2.Public.enabled
+ when: not in_check_mode
+
+- name: Test firewall_off2 (check-mode)
+ assert:
+ that:
+ - firewall_off2 is not changed
+ - not firewall_off2.Domain.enabled
+ - not firewall_off2.Private.enabled
+ - not firewall_off2.Public.enabled
+ when: in_check_mode
+
+
+- name: Turn off Windows Firewall again
+ win_firewall:
+ profiles: [ Domain, Private, Public ]
+ state: disabled
+ register: firewall_off2_again
+
+- name: Test firewall_off2_again (normal mode)
+ assert:
+ that:
+ - firewall_off2_again is not changed
+ - not firewall_off2_again.Domain.enabled
+ - not firewall_off2_again.Private.enabled
+ - not firewall_off2_again.Public.enabled
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_firewall_rule/aliases b/ansible_collections/community/windows/tests/integration/targets/win_firewall_rule/aliases
new file mode 100644
index 000000000..4cd27b3cb
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_firewall_rule/aliases
@@ -0,0 +1 @@
+shippable/windows/group1
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_firewall_rule/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_firewall_rule/tasks/main.yml
new file mode 100644
index 000000000..21fe38196
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_firewall_rule/tasks/main.yml
@@ -0,0 +1,609 @@
+- name: Remove potentially leftover firewall rule
+ win_firewall_rule:
+ name: http
+ state: absent
+ action: allow
+ direction: in
+
+- name: Add firewall rule
+ win_firewall_rule:
+ name: http
+ enabled: yes
+ state: present
+ localport: 80
+ action: allow
+ direction: in
+ protocol: tcp
+ register: add_firewall_rule
+
+- name: Check that creating new firewall rule succeeds with a change
+ assert:
+ that:
+ - add_firewall_rule.changed == true
+
+- name: Add same firewall rule (again)
+ win_firewall_rule:
+ name: http
+ enabled: yes
+ state: present
+ localport: 80
+ action: allow
+ direction: in
+ protocol: tcp
+ register: add_firewall_rule_again
+
+- name: Check that creating same firewall rule succeeds without a change
+ assert:
+ that:
+ - add_firewall_rule_again.changed == false
+
+- name: Remove firewall rule
+ win_firewall_rule:
+ name: http
+ enabled: yes
+ state: absent
+ localport: 80
+ action: allow
+ direction: in
+ protocol: tcp
+ register: remove_firewall_rule
+
+- name: Check that removing existing firewall rule succeeds with a change
+ assert:
+ that:
+ - remove_firewall_rule.changed == true
+
+- name: Remove absent firewall rule
+ win_firewall_rule:
+ name: http
+ enabled: yes
+ state: absent
+ localport: 80
+ action: allow
+ direction: in
+ protocol: tcp
+ register: remove_absent_firewall_rule
+
+- name: Check that removing non existing firewall rule succeeds without a change
+ assert:
+ that:
+ - remove_absent_firewall_rule.changed == false
+
+- name: Add firewall rule
+ win_firewall_rule:
+ name: http
+ enabled: no
+ state: present
+ group: application
+ localport: 80
+ action: allow
+ direction: in
+ protocol: tcp
+ register: add_firewall_rule
+
+- name: Check that creating new firewall rule succeeds with a change
+ assert:
+ that:
+ - add_firewall_rule.changed == true
+
+- name: Enable all the rules in application group
+ win_firewall_rule:
+ group: application
+ enabled: yes
+ register: change_firewall_rule
+
+- name: Check if the rules are enabled in application group
+ assert:
+ that:
+ - change_firewall_rule.changed == true
+
+- name: Enable all the rules in application group (again)
+ win_firewall_rule:
+ group: application
+ enabled: yes
+ register: change_firewall_rule
+
+- name: Check if the rules are enabled without a change
+ assert:
+ that:
+ - change_firewall_rule.changed == false
+
+- name: Disable all the rules in application group
+ win_firewall_rule:
+ group: application
+ enabled: no
+ register: change_firewall_rule
+
+- name: Check if the rules are disabled
+ assert:
+ that:
+ - change_firewall_rule.changed == true
+
+- name: Disable all the rules in application group (again)
+ win_firewall_rule:
+ group: application
+ enabled: no
+ register: change_firewall_rule
+
+- name: Check if the rules are disabled without a change
+ assert:
+ that:
+ - change_firewall_rule.changed == false
+
+- name: Remove firewall rule
+ win_firewall_rule:
+ name: http
+ enabled: no
+ state: absent
+ localport: 80
+ action: allow
+ group: application
+ direction: in
+ protocol: tcp
+ register: remove_firewall_rule
+
+- name: Check that removing existing firewall rule succeeds with a change
+ assert:
+ that:
+ - remove_firewall_rule.changed == true
+
+- name: Add firewall rule
+ win_firewall_rule:
+ name: http
+ enabled: yes
+ state: present
+ localport: 80
+ action: allow
+ direction: in
+ protocol: tcp
+
+- name: Change firewall rule
+ win_firewall_rule:
+ name: http
+ enabled: yes
+ state: present
+ localport: 80
+ action: block
+ direction: in
+ protocol: tcp
+ register: change_firewall_rule
+
+- name: Check that changing firewall rule succeeds
+ assert:
+ that:
+ - change_firewall_rule.changed == true
+
+- name: Disable firewall rule
+ win_firewall_rule:
+ name: http
+ enabled: no
+
+- name: Get the actual values from the changed firewall rule
+ ansible.windows.win_shell: '(New-Object -ComObject HNetCfg.FwPolicy2).Rules | Where-Object { $_.Name -eq "http" } | Foreach-Object { $_.LocalPorts; $_.Enabled; $_.Action; $_.Direction; $_.Protocol }'
+ register: firewall_rule_actual
+
+- name: Ensure that disabling the rule did not change the previous values
+ assert:
+ that:
+ - "firewall_rule_actual.stdout_lines[0] == '80'" # LocalPorts = 80
+ - "firewall_rule_actual.stdout_lines[1] == 'False'" # Enabled = False
+ - "firewall_rule_actual.stdout_lines[2] == '0'" # Action = block
+ - "firewall_rule_actual.stdout_lines[3] == '1'" # Direction = in
+ - "firewall_rule_actual.stdout_lines[4] == '6'" # Protocol = tcp
+
+- name: Add firewall rule when remoteip is range
+ win_firewall_rule:
+ name: http
+ enabled: yes
+ state: present
+ localport: 80
+ remoteip: 192.168.0.1-192.168.0.5
+ action: allow
+ direction: in
+ protocol: tcp
+
+- name: Add same firewall rule when remoteip is range (again)
+ win_firewall_rule:
+ name: http
+ enabled: yes
+ state: present
+ localport: 80
+ remoteip: 192.168.0.1-192.168.0.5
+ action: allow
+ direction: in
+ protocol: tcp
+ register: add_firewall_rule_with_range_remoteip_again
+
+- name: Check that creating same firewall rule when remoteip is range succeeds without a change
+ assert:
+ that:
+ - add_firewall_rule_with_range_remoteip_again.changed == false
+
+- name: Add firewall rule when remoteip in CIDR notation
+ win_firewall_rule:
+ name: http
+ enabled: yes
+ state: present
+ localport: 80
+ remoteip: 192.168.0.0/24
+ action: allow
+ direction: in
+ protocol: tcp
+
+- name: Add same firewall rule when remoteip in CIDR notation (again)
+ win_firewall_rule:
+ name: http
+ enabled: yes
+ state: present
+ localport: 80
+ remoteip: 192.168.0.0/24
+ action: allow
+ direction: in
+ protocol: tcp
+ register: add_firewall_rule_with_cidr_remoteip_again
+
+- name: Check that creating same firewall rule succeeds without a change when remoteip in CIDR notation
+ assert:
+ that:
+ - add_firewall_rule_with_cidr_remoteip_again.changed == false
+
+- name: Add firewall rule when remoteip contains a netmask
+ win_firewall_rule:
+ name: http
+ enabled: yes
+ state: present
+ localport: 80
+ remoteip: 192.168.1.0/255.255.255.0
+ action: allow
+ direction: in
+ protocol: tcp
+
+- name: Add same firewall rule when remoteip contains a netmask (again)
+ win_firewall_rule:
+ name: http
+ enabled: yes
+ state: present
+ localport: 80
+ remoteip: 192.168.1.0/255.255.255.0
+ action: allow
+ direction: in
+ protocol: tcp
+ register: add_firewall_rule_remoteip_contains_netmask_again
+
+- name: Check that creating same firewall rule succeeds without a change when remoteip contains a netmask
+ assert:
+ that:
+ - add_firewall_rule_remoteip_contains_netmask_again.changed == false
+
+- name: Add firewall rule when remoteip is IPv4
+ win_firewall_rule:
+ name: http
+ enabled: yes
+ state: present
+ localport: 80
+ remoteip: 192.168.0.1
+ action: allow
+ direction: in
+ protocol: tcp
+
+- name: Add same firewall rule when remoteip is IPv4 (again)
+ win_firewall_rule:
+ name: http
+ enabled: yes
+ state: present
+ localport: 80
+ remoteip: 192.168.0.1
+ action: allow
+ direction: in
+ protocol: tcp
+ register: add_firewall_rule_with_ipv4_remoteip_again
+
+- name: Check that creating same firewall rule when remoteip is IPv4 succeeds without a change
+ assert:
+ that:
+ - add_firewall_rule_with_ipv4_remoteip_again.changed == false
+
+- name: Add firewall rule when remoteip contains a netmask
+ win_firewall_rule:
+ name: http
+ enabled: yes
+ state: present
+ localport: 80
+ remoteip: 192.168.2.0/255.255.255.0
+ action: allow
+ direction: in
+ protocol: tcp
+
+- name: Add same firewall rule when remoteip in CIDR notation
+ win_firewall_rule:
+ name: http
+ enabled: yes
+ state: present
+ localport: 80
+ remoteip: 192.168.2.0/24
+ action: allow
+ direction: in
+ protocol: tcp
+ register: add_same_firewall_rule_with_cidr_remoteip
+
+- name: Check that creating same firewall rule succeeds without a change when remoteip contains a netmask or CIDR
+ assert:
+ that:
+ - add_same_firewall_rule_with_cidr_remoteip.changed == false
+
+- name: Add firewall rule with multiple ports
+ win_firewall_rule:
+ name: http
+ enabled: yes
+ state: present
+ localport: '80,81'
+ action: allow
+ direction: in
+ protocol: tcp
+ register: add_firewall_rule_with_multiple_ports
+
+- name: Check that creating firewall rule with multiple ports succeeds with a change
+ assert:
+ that:
+ - add_firewall_rule_with_multiple_ports.changed == true
+
+- name: Add firewall rule with interface types in string format
+ win_firewall_rule:
+ name: http
+ enabled: yes
+ state: present
+ localport: 80
+ action: allow
+ direction: in
+ protocol: tcp
+ interfacetypes: 'ras,lan,wireless'
+ register: add_firewall_rule_with_string_interface_types
+
+- name: Check that creating firewall rule with interface types in string format succeeds with a change
+ assert:
+ that:
+ - add_firewall_rule_with_string_interface_types.changed == true
+
+- name: Add firewall rule with interface types in list format
+ win_firewall_rule:
+ name: http
+ enabled: yes
+ state: present
+ localport: 80
+ action: allow
+ direction: in
+ protocol: tcp
+ interfacetypes: [ras, lan]
+ register: add_firewall_rule_with_list_interface_types
+
+- name: Check that creating firewall rule with interface types in list format succeeds with a change
+ assert:
+ that:
+ - add_firewall_rule_with_list_interface_types.changed == true
+
+- name: Add firewall rule with interface type 'any'
+ win_firewall_rule:
+ name: http
+ enabled: yes
+ state: present
+ localport: 80
+ action: allow
+ direction: in
+ protocol: tcp
+ interfacetypes: any
+ register: add_firewall_rule_with_interface_type_any
+
+- name: Check that creating firewall rule with interface type 'any' succeeds with a change
+ assert:
+ that:
+ - add_firewall_rule_with_interface_type_any.changed == true
+
+- name: Add firewall rule with edge traversal option 'deferapp'
+ win_firewall_rule:
+ name: http
+ enabled: yes
+ state: present
+ localport: 80
+ action: allow
+ direction: in
+ protocol: tcp
+ edge: deferapp
+ register: add_firewall_rule_with_edge_traversal
+
+# Setup action creates ansible_distribution_version variable
+- ansible.windows.setup:
+
+- name: Check that creating firewall rule with enge traversal option 'deferapp' succeeds with a change
+ assert:
+ that:
+ - add_firewall_rule_with_edge_traversal.changed == true
+ # Works on windows >= Windows 7/Windows Server 2008 R2
+ when: ansible_distribution_version is version('6.1', '>=')
+
+- name: Add firewall rule with 'authenticate' secure flag
+ win_firewall_rule:
+ name: http
+ enabled: yes
+ state: present
+ localport: 80
+ action: allow
+ direction: in
+ protocol: tcp
+ security: authenticate
+ register: add_firewall_rule_with_secure_flags
+
+- name: Check that creating firewall rule with secure flag 'authenticate' succeeds with a change
+ assert:
+ that:
+ - add_firewall_rule_with_secure_flags.changed == true
+ # Works on windows >= Windows 8/Windows Server 2012
+ when: ansible_distribution_version is version('6.2', '>=')
+
+- name: Add firewall rule with profiles in string format
+ win_firewall_rule:
+ name: http
+ enabled: yes
+ state: present
+ localport: 80
+ action: allow
+ direction: in
+ protocol: tcp
+ profiles: 'domain,public'
+ register: add_firewall_rule_with_string_profiles
+
+- name: Check that creating firewall rule with profiles in string format succeeds with a change
+ assert:
+ that:
+ - add_firewall_rule_with_string_profiles.changed == true
+
+- name: Set firewall rule profile back to 'all'
+ win_firewall_rule:
+ name: http
+ enabled: yes
+ state: present
+ localport: 80
+ action: allow
+ direction: in
+ protocol: tcp
+ profiles: [Domain, Public, Private]
+ register: add_firewall_rule_with_string_profiles
+
+- name: Check that setting firewall rule profile back to 'all' succeeds with a change
+ assert:
+ that:
+ - add_firewall_rule_with_string_profiles.changed == true
+
+- name: Add firewall rule with profiles in list format
+ win_firewall_rule:
+ name: http
+ enabled: yes
+ state: present
+ localport: 80
+ action: allow
+ direction: in
+ protocol: tcp
+ profiles: [Domain, Private]
+ register: add_firewall_rule_with_list_profiles
+
+- name: Check that creating firewall rule with profiles in list format succeeds with a change
+ assert:
+ that:
+ - add_firewall_rule_with_list_profiles.changed == true
+
+# Test for variable expansion in the path
+- name: Add rule with path that needs to be expanded
+ win_firewall_rule:
+ name: VarExpansionTest
+ enabled: yes
+ state: present
+ action: allow
+ direction: in
+ protocol: tcp
+ program: '%SystemRoot%\system32\svchost.exe'
+
+- name: Add same rule with path that needs to be expanded
+ win_firewall_rule:
+ name: VarExpansionTest
+ enabled: yes
+ state: present
+ action: allow
+ direction: in
+ protocol: tcp
+ program: '%SystemRoot%\system32\svchost.exe'
+ register: add_firewall_rule_with_var_expand_path
+
+- name: Check that creating same firewall rule with expanded vars identified
+ assert:
+ that:
+ - add_firewall_rule_with_var_expand_path.changed == false
+
+- name: Add firewall rule for application group
+ win_firewall_rule:
+ name: Rule for application group
+ enabled: yes
+ state: present
+ localport: 80
+ action: allow
+ direction: in
+ protocol: tcp
+ group: application
+ register: add_firewall_rule_with_group
+
+- name: Check that creating firewall rule for application group succeeds with a change
+ assert:
+ that:
+ - add_firewall_rule_with_group.changed == true
+
+# Test icmptypecode
+- name: Add rule with icmptypecode
+ win_firewall_rule:
+ name: icmptest
+ enabled: yes
+ state: present
+ action: allow
+ direction: in
+ protocol: icmpv4
+ icmp_type_code: '8:*'
+ register: add_firewall_rule_with_icmptypecode
+
+- name: Check that creating same firewall rule with expanded vars identified
+ assert:
+ that:
+ - add_firewall_rule_with_icmptypecode.changed == true
+
+- name: Remove rule with icmptypecode
+ win_firewall_rule:
+ name: icmptest
+ enabled: yes
+ state: absent
+ action: allow
+ direction: in
+ protocol: icmpv4
+ icmp_type_code: '8:*'
+ register: remove_firewall_rule_with_icmptypecode
+
+- name: Check that removing same firewall rule with expanded vars identified
+ assert:
+ that:
+ - remove_firewall_rule_with_icmptypecode.changed == true
+
+# test for application name / program changes to any (and if they null the property)
+# -----------------------------------------------------------------------------
+- name: Add rule with an accociated program
+ win_firewall_rule:
+ name: ApplicationToAnyTest
+ enabled: true
+ state: present
+ action: allow
+ direction: in
+ protocol: tcp
+ program: '%SystemRoot%\system32\svchost.exe'
+ register: add_firewall_rule_with_program
+
+- name: Check that creating firewall rule succeeds with a change
+ ansible.builtin.assert:
+ that:
+ - add_firewall_rule_with_program.changed == true
+
+- name: Add same rule with program set to any
+ win_firewall_rule:
+ name: ApplicationToAnyTest
+ enabled: true
+ state: present
+ action: allow
+ direction: in
+ protocol: tcp
+ program: any
+ register: change_firewall_rule_with_program
+
+- name: Check that changing firewall rule succeeds with a change
+ ansible.builtin.assert:
+ that:
+ - change_firewall_rule_with_program.changed == true
+
+- name: Get the actual values from the changed firewall rule and check if ApplicationName is null
+ ansible.windows.win_shell: >-
+ ((New-Object -ComObject HNetCfg.FwPolicy2).Rules | Where-Object { $_.Name -eq "ApplicationToAnyTest" } | Foreach-Object { $_.ApplicationName }) -eq $null
+ register: firewall_rule_actual
+ failed_when: 'firewall_rule_actual.stdout_lines[0] != "True"'
+# -----------------------------------------------------------------------------
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_format/aliases b/ansible_collections/community/windows/tests/integration/targets/win_format/aliases
new file mode 100644
index 000000000..4f4664b68
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_format/aliases
@@ -0,0 +1 @@
+shippable/windows/group5
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_format/meta/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_format/meta/main.yml
new file mode 100644
index 000000000..9f37e96cd
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_format/meta/main.yml
@@ -0,0 +1,2 @@
+dependencies:
+- setup_remote_tmp_dir
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_format/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_format/tasks/main.yml
new file mode 100644
index 000000000..5ea27a6f0
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_format/tasks/main.yml
@@ -0,0 +1,7 @@
+---
+- name: Check if Format-Volume is supported
+ ansible.windows.win_shell: if (Get-Command -Name Format-Volume -ErrorAction SilentlyContinue) { $true } else { $false }
+ register: module_present
+
+- include: pre_test.yml
+ when: module_present.stdout | trim | bool
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_format/tasks/pre_test.yml b/ansible_collections/community/windows/tests/integration/targets/win_format/tasks/pre_test.yml
new file mode 100644
index 000000000..a29a47bbe
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_format/tasks/pre_test.yml
@@ -0,0 +1,21 @@
+---
+- set_fact:
+ AnsibleVhdx: '{{ remote_tmp_dir }}\AnsiblePart.vhdx'
+
+- name: Copy VHDX scripts
+ ansible.windows.win_template:
+ src: "{{ item.src }}"
+ dest: '{{ remote_tmp_dir }}\{{ item.dest }}'
+ loop:
+ - { src: partition_creation_script.j2, dest: partition_creation_script.txt }
+ - { src: partition_deletion_script.j2, dest: partition_deletion_script.txt }
+
+- name: Create partition
+ ansible.windows.win_command: diskpart.exe /s {{ remote_tmp_dir }}\partition_creation_script.txt
+
+- name: Run tests
+ block:
+ - include: tests.yml
+ always:
+ - name: Detach disk
+ ansible.windows.win_command: diskpart.exe /s {{ remote_tmp_dir }}\partition_deletion_script.txt
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_format/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_format/tasks/tests.yml
new file mode 100644
index 000000000..1383c6f9c
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_format/tasks/tests.yml
@@ -0,0 +1,182 @@
+---
+- ansible.windows.win_shell: $AnsiPart = Get-Partition -DriveLetter T; $AnsiVol = Get-Volume -DriveLetter T; "$($AnsiPart.Size),$($AnsiVol.Size)"
+ register: shell_result
+
+- name: Assert volume size is 0 for pristine volume
+ assert:
+ that:
+ - shell_result.stdout | trim == "2096037888,0"
+
+- name: Get partition access path
+ ansible.windows.win_shell: (Get-Partition -DriveLetter T).AccessPaths[1]
+ register: shell_partition_result
+
+- name: Try to format using mutually exclusive parameters
+ win_format:
+ drive_letter: T
+ path: "{{ shell_partition_result.stdout | trim }}"
+ register: format_mutex_result
+ ignore_errors: True
+
+- assert:
+ that:
+ - format_mutex_result is failed
+ - 'format_mutex_result.msg == "parameters are mutually exclusive: drive_letter, path, label"'
+
+- name: Fully format volume and assign label (check)
+ win_format:
+ drive_letter: T
+ new_label: Formatted
+ full: True
+ allocation_unit_size: 8192
+ register: format_result_check
+ check_mode: True
+
+- ansible.windows.win_shell: $AnsiPart = Get-Partition -DriveLetter T; $AnsiVol = Get-Volume -DriveLetter T; "$($AnsiPart.Size),$($AnsiVol.Size),$($AnsiVol.FileSystemLabel),$((Get-CimInstance -ClassName Win32_Volume -Filter "DriveLetter = 'T:'" -Property BlockSize).BlockSize)"
+ register: formatted_value_result_check
+
+- name: Fully format volume and assign label
+ win_format:
+ drive_letter: T
+ new_label: Formatted
+ full: True
+ allocation_unit_size: 8192
+ register: format_result
+
+- ansible.windows.win_shell: $AnsiPart = Get-Partition -DriveLetter T; $AnsiVol = Get-Volume -DriveLetter T; "$($AnsiPart.Size),$($AnsiVol.Size),$($AnsiVol.FileSystemLabel),$((Get-CimInstance -ClassName Win32_Volume -Filter "DriveLetter = 'T:'" -Property BlockSize).BlockSize)"
+ register: formatted_value_result
+
+- assert:
+ that:
+ - format_result_check is changed
+ - format_result is changed
+ - formatted_value_result_check.stdout | trim == "2096037888,0,,"
+ - formatted_value_result.stdout | trim == "2096037888,2096029696,Formatted,8192"
+
+- name: Format NTFS volume with integrity streams enabled
+ win_format:
+ path: "{{ shell_partition_result.stdout | trim }}"
+ file_system: ntfs
+ integrity_streams: True
+ ignore_errors: True
+ register: ntfs_integrity_streams
+
+- assert:
+ that:
+ - ntfs_integrity_streams is failed
+ - 'ntfs_integrity_streams.msg == "Integrity streams can be enabled only on ReFS volumes. You specified: ntfs"'
+
+- name: Format volume (require force_format for specifying different file system)
+ win_format:
+ path: "{{ shell_partition_result.stdout | trim }}"
+ file_system: fat32
+ ignore_errors: True
+ register: require_force_format
+
+- assert:
+ that:
+ - require_force_format is failed
+ - 'require_force_format.msg == "Force format must be specified since target file system: fat32 is different from the current file system of the volume: ntfs"'
+
+- name: Format volume (forced) (check)
+ win_format:
+ path: "{{ shell_partition_result.stdout | trim }}"
+ file_system: refs
+ force: True
+ check_mode: True
+ ignore_errors: True
+ register: not_pristine_forced_check
+
+- name: Format volume (forced)
+ win_format:
+ path: "{{ shell_partition_result.stdout | trim }}"
+ file_system: refs
+ force: True
+ register: not_pristine_forced
+
+- name: Format volume (forced) (idempotence will not work)
+ win_format:
+ path: "{{ shell_partition_result.stdout | trim }}"
+ file_system: refs
+ force: True
+ register: not_pristine_forced_idem_fails
+
+- name: Format volume (idempotence)
+ win_format:
+ path: "{{ shell_partition_result.stdout | trim }}"
+ file_system: refs
+ register: not_pristine_forced_idem
+
+- assert:
+ that:
+ - not_pristine_forced_check is changed
+ - not_pristine_forced is changed
+ - not_pristine_forced_idem_fails is changed
+ - not_pristine_forced_idem is not changed
+
+- name: Add a file
+ ansible.windows.win_file:
+ path: T:\path\to\directory
+ state: directory
+
+- name: Format volume with file inside without force and same fs
+ win_format:
+ path: "{{ shell_partition_result.stdout | trim }}"
+ register: format_volume_without_force_same_fs
+
+- name: Format volume (forced) - to test case for files existing and a different fs
+ win_format:
+ path: "{{ shell_partition_result.stdout | trim }}"
+ file_system: ntfs
+ force: True
+
+- name: Add a file
+ ansible.windows.win_file:
+ path: T:\path\to\directory
+ state: directory
+ register: add_file_to_volume
+
+- name: Format volume with file inside without force
+ win_format:
+ path: "{{ shell_partition_result.stdout | trim }}"
+ file_system: refs
+ register: format_volume_without_force
+ ignore_errors: True
+
+- name: Format volume with file inside with force
+ win_format:
+ path: "{{ shell_partition_result.stdout | trim }}"
+ force: True
+ register: format_volume_with_force
+
+- assert:
+ that:
+ - add_file_to_volume is changed
+ - format_volume_without_force is failed
+ - format_volume_without_force_same_fs is not changed
+ - 'format_volume_without_force.msg == "Force format must be specified to format non-pristine volumes"'
+ - format_volume_with_force is changed
+
+- name: Reformat using different alu without force format
+ win_format:
+ path: "{{ shell_partition_result.stdout | trim }}"
+ allocation_unit_size: 8192
+ file_system: ntfs
+ register: reformat_using_alu_without_force
+ ignore_errors: True
+
+- assert:
+ that:
+ - reformat_using_alu_without_force is failed
+
+- name: Reformat using different alu using force format
+ win_format:
+ path: "{{ shell_partition_result.stdout | trim }}"
+ allocation_unit_size: 8192
+ file_system: ntfs
+ force: True
+ register: reformat_using_alu_with_force
+
+- assert:
+ that:
+ - reformat_using_alu_with_force is changed
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_format/templates/partition_creation_script.j2 b/ansible_collections/community/windows/tests/integration/targets/win_format/templates/partition_creation_script.j2
new file mode 100644
index 000000000..8e47fda95
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_format/templates/partition_creation_script.j2
@@ -0,0 +1,11 @@
+create vdisk file="{{ AnsibleVhdx }}" maximum=2000 type=fixed
+
+select vdisk file="{{ AnsibleVhdx }}"
+
+attach vdisk
+
+convert mbr
+
+create partition primary
+
+assign letter="T"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_format/templates/partition_deletion_script.j2 b/ansible_collections/community/windows/tests/integration/targets/win_format/templates/partition_deletion_script.j2
new file mode 100644
index 000000000..c2be9cd14
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_format/templates/partition_deletion_script.j2
@@ -0,0 +1,3 @@
+select vdisk file="{{ AnsibleVhdx }}"
+
+detach vdisk
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_hosts/aliases b/ansible_collections/community/windows/tests/integration/targets/win_hosts/aliases
new file mode 100644
index 000000000..4cd27b3cb
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_hosts/aliases
@@ -0,0 +1 @@
+shippable/windows/group1
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_hosts/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_hosts/defaults/main.yml
new file mode 100644
index 000000000..c6270216d
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_hosts/defaults/main.yml
@@ -0,0 +1,13 @@
+---
+test_win_hosts_cname: testhost
+test_win_hosts_ip: 192.168.168.1
+
+test_win_hosts_aliases_set:
+ - alias1
+ - alias2
+ - alias3
+ - alias4
+
+test_win_hosts_aliases_remove:
+ - alias3
+ - alias4
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_hosts/meta/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_hosts/meta/main.yml
new file mode 100644
index 000000000..9f37e96cd
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_hosts/meta/main.yml
@@ -0,0 +1,2 @@
+dependencies:
+- setup_remote_tmp_dir
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_hosts/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_hosts/tasks/main.yml
new file mode 100644
index 000000000..02a8b873e
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_hosts/tasks/main.yml
@@ -0,0 +1,17 @@
+---
+- name: take a copy of the original hosts file
+ ansible.windows.win_copy:
+ src: C:\Windows\System32\drivers\etc\hosts
+ dest: '{{ remote_tmp_dir }}\hosts'
+ remote_src: yes
+
+- block:
+ - name: run tests
+ include_tasks: tests.yml
+
+ always:
+ - name: restore hosts file
+ ansible.windows.win_copy:
+ src: '{{ remote_tmp_dir }}\hosts'
+ dest: C:\Windows\System32\drivers\etc\hosts
+ remote_src: yes
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_hosts/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_hosts/tasks/tests.yml
new file mode 100644
index 000000000..5ced7ba26
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_hosts/tasks/tests.yml
@@ -0,0 +1,189 @@
+---
+
+- name: add a simple host with address
+ win_hosts:
+ state: present
+ ip_address: "{{ test_win_hosts_ip }}"
+ canonical_name: "{{ test_win_hosts_cname }}"
+ register: add_ip
+
+- assert:
+ that:
+ - "add_ip.changed == true"
+
+- name: get actual dns result
+ ansible.windows.win_shell: "try{ [array]$t = [Net.DNS]::GetHostEntry('{{ test_win_hosts_cname }}') } catch { return 'false' } if ($t[0].HostName -eq '{{ test_win_hosts_cname }}' -and $t[0].AddressList[0].toString() -eq '{{ test_win_hosts_ip }}'){ return 'true' } else { return 'false' }"
+ register: add_ip_actual
+
+- assert:
+ that:
+ - "add_ip_actual.stdout_lines[0]|lower == 'true'"
+
+- name: add a simple host with ipv4 address (idempotent)
+ win_hosts:
+ state: present
+ ip_address: "{{ test_win_hosts_ip }}"
+ canonical_name: "{{ test_win_hosts_cname }}"
+ register: add_ip
+
+- assert:
+ that:
+ - "add_ip.changed == false"
+
+- name: remove simple host
+ win_hosts:
+ state: absent
+ ip_address: "{{ test_win_hosts_ip }}"
+ canonical_name: "{{ test_win_hosts_cname }}"
+ register: remove_ip
+
+- assert:
+ that:
+ - "remove_ip.changed == true"
+
+- name: get actual dns result
+ ansible.windows.win_shell: "try{ [array]$t = [Net.DNS]::GetHostEntry('{{ test_win_hosts_cname}}') } catch { return 'false' } if ($t[0].HostName -eq '{{ test_win_hosts_cname }}' -and $t[0].AddressList[0].toString() -eq '{{ test_win_hosts_ip }}'){ return 'true' } else { return 'false' }"
+ register: remove_ip_actual
+ failed_when: "remove_ip_actual.rc == 0"
+
+- assert:
+ that:
+ - "remove_ip_actual.stdout_lines[0]|lower == 'false'"
+
+- name: remove simple host (idempotent)
+ win_hosts:
+ state: absent
+ ip_address: "{{ test_win_hosts_ip }}"
+ canonical_name: "{{ test_win_hosts_cname }}"
+ register: remove_ip
+
+- assert:
+ that:
+ - "remove_ip.changed == false"
+
+- name: add host and set aliases
+ win_hosts:
+ state: present
+ ip_address: "{{ test_win_hosts_ip }}"
+ canonical_name: "{{ test_win_hosts_cname }}"
+ aliases: "{{ test_win_hosts_aliases_set | union(test_win_hosts_aliases_remove) }}"
+ action: set
+ register: set_aliases
+
+- assert:
+ that:
+ - "set_aliases.changed == true"
+
+- name: get actual dns result for host
+ ansible.windows.win_shell: "try{ [array]$t = [Net.DNS]::GetHostEntry('{{ test_win_hosts_cname }}') } catch { return 'false' } if ($t[0].HostName -eq '{{ test_win_hosts_cname }}' -and $t[0].AddressList[0].toString() -eq '{{ test_win_hosts_ip }}'){ return 'true' } else { return 'false' }"
+ register: set_aliases_actual_host
+
+- assert:
+ that:
+ - "set_aliases_actual_host.stdout_lines[0]|lower == 'true'"
+
+- name: get actual dns results for aliases
+ ansible.windows.win_shell: "try{ [array]$t = [Net.DNS]::GetHostEntry('{{ item }}') } catch { return 'false' } if ($t[0].HostName -eq '{{ test_win_hosts_cname }}' -and $t[0].AddressList[0].toString() -eq '{{ test_win_hosts_ip }}'){ return 'true' } else { return 'false' }"
+ register: set_aliases_actual
+ with_items: "{{ test_win_hosts_aliases_set | union(test_win_hosts_aliases_remove) }}"
+
+- assert:
+ that:
+ - "item.stdout_lines[0]|lower == 'true'"
+ with_items: "{{ set_aliases_actual.results }}"
+
+- name: add host and set aliases (idempotent)
+ win_hosts:
+ state: present
+ ip_address: "{{ test_win_hosts_ip }}"
+ canonical_name: "{{ test_win_hosts_cname }}"
+ aliases: "{{ test_win_hosts_aliases_set | union(test_win_hosts_aliases_remove) }}"
+ action: set
+ register: set_aliases
+
+- assert:
+ that:
+ - "set_aliases.changed == false"
+
+- name: remove aliases from the list
+ win_hosts:
+ state: present
+ ip_address: "{{ test_win_hosts_ip }}"
+ canonical_name: "{{ test_win_hosts_cname }}"
+ aliases: "{{ test_win_hosts_aliases_remove }}"
+ action: remove
+ register: remove_aliases
+
+- assert:
+ that:
+ - "remove_aliases.changed == true"
+
+- name: get actual dns result for removed aliases
+ ansible.windows.win_shell: "try{ [array]$t = [Net.DNS]::GetHostEntry('{{ item }}') } catch { return 'false' } if ($t[0].HostName -eq '{{ test_win_hosts_cname }}' -and $t[0].AddressList[0].toString() -eq '{{ test_win_hosts_ip }}'){ return 'true' } else { return 'false' }"
+ register: remove_aliases_removed_actual
+ failed_when: "remove_aliases_removed_actual.rc == 0"
+ with_items: "{{ test_win_hosts_aliases_remove }}"
+
+- assert:
+ that:
+ - "item.stdout_lines[0]|lower == 'false'"
+ with_items: "{{ remove_aliases_removed_actual.results }}"
+
+- name: get actual dns result for remaining aliases
+ ansible.windows.win_shell: "try{ [array]$t = [Net.DNS]::GetHostEntry('{{ item }}') } catch { return 'false' } if ($t[0].HostName -eq '{{ test_win_hosts_cname }}' -and $t[0].AddressList[0].toString() -eq '{{ test_win_hosts_ip }}'){ return 'true' } else { return 'false' }"
+ register: remove_aliases_remain_actual
+ with_items: "{{ test_win_hosts_aliases_set | difference(test_win_hosts_aliases_remove) }}"
+
+- assert:
+ that:
+ - "item.stdout_lines[0]|lower == 'true'"
+ with_items: "{{ remove_aliases_remain_actual.results }}"
+
+- name: remove aliases from the list (idempotent)
+ win_hosts:
+ state: present
+ ip_address: "{{ test_win_hosts_ip }}"
+ canonical_name: "{{ test_win_hosts_cname }}"
+ aliases: "{{ test_win_hosts_aliases_remove }}"
+ action: remove
+ register: remove_aliases
+
+- assert:
+ that:
+ - "remove_aliases.changed == false"
+
+- name: add aliases back
+ win_hosts:
+ state: present
+ ip_address: "{{ test_win_hosts_ip }}"
+ canonical_name: "{{ test_win_hosts_cname }}"
+ aliases: "{{ test_win_hosts_aliases_remove }}"
+ action: add
+ register: add_aliases
+
+- assert:
+ that:
+ - "add_aliases.changed == true"
+
+- name: get actual dns results for aliases
+ ansible.windows.win_shell: "try{ [array]$t = [Net.DNS]::GetHostEntry('{{ item }}') } catch { return 'false' } if ($t[0].HostName -eq '{{ test_win_hosts_cname }}' -and $t[0].AddressList[0].toString() -eq '{{ test_win_hosts_ip }}'){ return 'true' } else { return 'false' }"
+ register: add_aliases_actual
+ with_items: "{{ test_win_hosts_aliases_set | union(test_win_hosts_aliases_remove) }}"
+
+- assert:
+ that:
+ - "item.stdout_lines[0]|lower == 'true'"
+ with_items: "{{ add_aliases_actual.results }}"
+
+- name: add aliases back (idempotent)
+ win_hosts:
+ state: present
+ ip_address: "{{ test_win_hosts_ip }}"
+ canonical_name: "{{ test_win_hosts_cname }}"
+ aliases: "{{ test_win_hosts_aliases_remove }}"
+ action: add
+ register: add_aliases
+
+- assert:
+ that:
+ - "add_aliases.changed == false"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_hotfix/aliases b/ansible_collections/community/windows/tests/integration/targets/win_hotfix/aliases
new file mode 100644
index 000000000..11addc63b
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_hotfix/aliases
@@ -0,0 +1,2 @@
+shippable/windows/group4
+unstable
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_hotfix/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_hotfix/defaults/main.yml
new file mode 100644
index 000000000..22edea7c1
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_hotfix/defaults/main.yml
@@ -0,0 +1,13 @@
+---
+# these hotfixes, are for Hyper-V, there may be a chance the system already has them
+# but in most cases for our CI purposes they wouldn't be present
+test_win_hotfix_good_url: https://ansible-ci-files.s3.amazonaws.com/test/integration/targets/win_hotfix/windows8.1-kb3027108-v2-x64_66366c7be2d64d83b63cac42bc40c0a3c01bc70d.msu
+test_win_hotfix_reboot_url: https://ansible-ci-files.s3.amazonaws.com/test/integration/targets/win_hotfix/windows8.1-kb2913659-v2-x64_963a4d890c9ff9cc83a97cf54305de6451038ba4.msu
+test_win_hotfix_bad_url: https://ansible-ci-files.s3.amazonaws.com/test/integration/targets/win_hotfix/windows8-rt-kb3172729-x64_69cab4c7785b1faa3fc450f32bed4873d53bb96f.msu
+test_win_hotfix_path: C:\ansible\win_hotfix
+
+test_win_hotfix_kb: KB3027108
+test_win_hotfix_identifier: Package_for_KB3027108~31bf3856ad364e35~amd64~~6.3.2.0
+
+test_win_hotfix_reboot_kb: KB2913659
+test_win_hotfix_reboot_identifier: Package_for_KB2913659~31bf3856ad364e35~amd64~~6.3.2.0
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_hotfix/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_hotfix/tasks/main.yml
new file mode 100644
index 000000000..47b2d3056
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_hotfix/tasks/main.yml
@@ -0,0 +1,54 @@
+---
+- name: filter servers that can support DISM
+ ansible.windows.win_command: powershell.exe "Import-Module -Name DISM"
+ register: eligable_servers
+ ignore_errors: True
+
+- name: fail to run module on servers that don't support DISM
+ win_hotfix:
+ path: fake
+ state: present
+ register: fail_no_dism
+ failed_when: fail_no_dism.msg != 'The DISM PS module needs to be installed, this can be done through the windows-adk chocolately package'
+ when: eligable_servers.rc != 0
+
+- name: run tests on hosts that support DISM
+ include_tasks: tests.yml
+ when: eligable_servers.rc == 0
+
+- name: set output to true if running Server 2012 R2
+ ansible.windows.win_command: powershell.exe "$version = [Environment]::OSVersion.Version; if ($version.Major -eq 6 -and $version.Minor -eq 3) { 'true' } else { 'false' }"
+ register: test_hotfix
+
+- block:
+ - name: ensure hotfixes are uninstalled before tests
+ win_hotfix:
+ hotfix_identifier: '{{item}}'
+ state: absent
+ register: pre_uninstall
+ with_items:
+ - '{{test_win_hotfix_identifier}}'
+ - '{{test_win_hotfix_reboot_identifier}}'
+
+ - name: reboot after pre test uninstall if required
+ ansible.windows.win_reboot:
+ when: pre_uninstall.results[0].reboot_required == True or pre_uninstall.results[1].reboot_required == True
+
+ - name: run actual hotfix tests on Server 2012 R2 only
+ include_tasks: tests_2012R2.yml
+
+ always:
+ - name: ensure hotfixes are uninstalled after tests
+ win_hotfix:
+ hotfix_identifier: '{{item}}'
+ state: absent
+ register: post_uninstall
+ with_items:
+ - '{{test_win_hotfix_identifier}}'
+ - '{{test_win_hotfix_reboot_identifier}}'
+
+ - name: reboot after post test uninstall if required
+ ansible.windows.win_reboot:
+ when: post_uninstall.results[0].reboot_required == True or post_uninstall.results[1].reboot_required == True
+
+ when: test_hotfix.stdout_lines[0] == "true"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_hotfix/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_hotfix/tasks/tests.yml
new file mode 100644
index 000000000..8e7a7df37
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_hotfix/tasks/tests.yml
@@ -0,0 +1,35 @@
+# only basic tests, doesn't actually install/uninstall and hotfixes
+---
+- name: fail when source isn't set
+ win_hotfix:
+ state: present
+ register: fail_no_source
+ failed_when: fail_no_source.msg != 'source must be set when state=present'
+
+- name: fail when identifier or kb isn't set on absent
+ win_hotfix:
+ state: absent
+ register: fail_no_key
+ failed_when: fail_no_key.msg != 'either hotfix_identifier or hotfix_kb needs to be set when state=absent'
+
+- name: remove an identifier that isn't installed
+ win_hotfix:
+ hotfix_identifier: fake~identifier
+ state: absent
+ register: remove_missing_hotfix_identifier
+
+- name: assert remove an identifier that isn't installed
+ assert:
+ that:
+ - remove_missing_hotfix_identifier is not changed
+
+- name: remove a kb that isn't installed
+ win_hotfix:
+ hotfix_kb: KB123456
+ state: absent
+ register: remove_missing_hotfix_kb
+
+- name: assert remove a kb that isn't installed
+ assert:
+ that:
+ - remove_missing_hotfix_kb is not changed
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_hotfix/tasks/tests_2012R2.yml b/ansible_collections/community/windows/tests/integration/targets/win_hotfix/tasks/tests_2012R2.yml
new file mode 100644
index 000000000..14ff38ec5
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_hotfix/tasks/tests_2012R2.yml
@@ -0,0 +1,265 @@
+---
+- name: create test staging folder
+ ansible.windows.win_file:
+ path: '{{test_win_hotfix_path}}'
+ state: directory
+
+- name: download hotfix
+ ansible.windows.win_get_url:
+ url: '{{test_win_hotfix_good_url}}'
+ dest: '{{test_win_hotfix_path}}\good.msu'
+ register: download_res
+ until: download_res is successful
+ retries: 3
+ delay: 5
+
+- name: download reboot hotfix
+ ansible.windows.win_get_url:
+ url: '{{test_win_hotfix_reboot_url}}'
+ dest: '{{test_win_hotfix_path}}\reboot.msu'
+ register: download_res
+ until: download_res is successful
+ retries: 3
+ delay: 5
+
+- name: download bad hotfix
+ ansible.windows.win_get_url:
+ url: '{{test_win_hotfix_bad_url}}'
+ dest: '{{test_win_hotfix_path}}\bad.msu'
+ register: download_res
+ until: download_res is successful
+ retries: 3
+ delay: 5
+
+- name: fail install install hotfix where kb doesn't match
+ win_hotfix:
+ hotfix_kb: KB0000000
+ source: '{{test_win_hotfix_path}}\good.msu'
+ state: present
+ register: fail_install_invalid_kb
+ failed_when: fail_install_invalid_kb.msg != 'the hotfix KB KB0000000 does not match with the source msu KB ' + test_win_hotfix_kb + ', please omit or specify the correct KB to continue'
+
+- name: fail install install hotfix where identifier doesn't match
+ win_hotfix:
+ hotfix_identifier: invalid
+ source: '{{test_win_hotfix_path}}\good.msu'
+ state: present
+ register: fail_install_invalid_identifier
+ failed_when: fail_install_invalid_identifier.msg != 'the hotfix identifier invalid does not match with the source msu identifier ' + test_win_hotfix_identifier + ', please omit or specify the correct identifier to continue'
+
+- name: fail install not applicable hotfix
+ win_hotfix:
+ source: '{{test_win_hotfix_path}}\bad.msu'
+ state: present
+ register: fail_install_not_applicable
+ failed_when: fail_install_not_applicable.msg != 'hotfix package is not applicable for this server'
+
+- name: install hotfix check
+ win_hotfix:
+ source: '{{test_win_hotfix_path}}\good.msu'
+ state: present
+ register: install_hotfix_check
+ check_mode: yes
+
+- name: get result of install hotfix check
+ ansible.windows.win_command: powershell.exe Get-Hotfix -Id {{test_win_hotfix_kb}}
+ register: install_hotfix_actual_check
+ ignore_errors: True
+
+- name: assert install hotfix check
+ assert:
+ that:
+ - install_hotfix_check is changed
+ - install_hotfix_check.kb == test_win_hotfix_kb
+ - install_hotfix_check.identifier == test_win_hotfix_identifier
+ - install_hotfix_actual_check.rc != 0
+
+- name: install hotfix
+ win_hotfix:
+ source: '{{test_win_hotfix_path}}\good.msu'
+ state: present
+ register: install_hotfix
+
+- name: get result of install hotfix
+ ansible.windows.win_command: powershell.exe Get-Hotfix -Id {{test_win_hotfix_kb}}
+ register: install_hotfix_actual
+
+- name: assert install hotfix
+ assert:
+ that:
+ - install_hotfix is changed
+ - install_hotfix.kb == test_win_hotfix_kb
+ - install_hotfix.identifier == test_win_hotfix_identifier
+ - install_hotfix.reboot_required == False
+ - install_hotfix_actual.rc == 0
+
+- name: install hotfix again
+ win_hotfix:
+ source: '{{test_win_hotfix_path}}\good.msu'
+ state: present
+ register: install_hotfix_again
+
+- name: assert install hotfix again
+ assert:
+ that:
+ - install_hotfix_again is not changed
+ - install_hotfix_again.kb == test_win_hotfix_kb
+ - install_hotfix_again.identifier == test_win_hotfix_identifier
+ - install_hotfix_again.reboot_required == False
+
+- name: uninstall hotfix check
+ win_hotfix:
+ hotfix_identifier: '{{test_win_hotfix_identifier}}'
+ state: absent
+ register: uninstall_hotfix_check
+ check_mode: yes
+
+- name: get result of uninstall hotfix check
+ ansible.windows.win_command: powershell.exe Get-Hotfix -Id {{test_win_hotfix_kb}}
+ register: uninstall_hotfix_actual_check
+
+- name: assert uninstall hotfix check
+ assert:
+ that:
+ - uninstall_hotfix_check is changed
+ - uninstall_hotfix_check.kb == test_win_hotfix_kb
+ - uninstall_hotfix_check.identifier == test_win_hotfix_identifier
+ - uninstall_hotfix_actual_check.rc == 0
+
+- name: uninstall hotfix
+ win_hotfix:
+ hotfix_identifier: '{{test_win_hotfix_identifier}}'
+ state: absent
+ register: uninstall_hotfix
+
+- name: get result of uninstall hotfix
+ ansible.windows.win_command: powershell.exe Get-Hotfix -Id {{test_win_hotfix_kb}}
+ register: uninstall_hotfix_actual
+ ignore_errors: True
+
+- name: assert uninstall hotfix
+ assert:
+ that:
+ - uninstall_hotfix is changed
+ - uninstall_hotfix.kb == test_win_hotfix_kb
+ - uninstall_hotfix.identifier == test_win_hotfix_identifier
+ - uninstall_hotfix.reboot_required == False
+ - uninstall_hotfix_actual.rc != 0
+
+- name: uninstall hotfix again
+ win_hotfix:
+ hotfix_identifier: '{{test_win_hotfix_identifier}}'
+ state: absent
+ register: uninstall_hotfix_again
+
+- name: assert uninstall hotfix again
+ assert:
+ that:
+ - uninstall_hotfix_again is not changed
+ - uninstall_hotfix_again.reboot_required == False
+
+- name: install reboot hotfix
+ win_hotfix:
+ hotfix_kb: '{{test_win_hotfix_reboot_kb}}'
+ source: '{{test_win_hotfix_path}}\reboot.msu'
+ state: present
+ register: install_reboot_hotfix
+
+- name: get result of install reboot hotfix
+ ansible.windows.win_command: powershell.exe Get-Hotfix -Id {{test_win_hotfix_reboot_kb}}
+ register: install_hotfix_reboot_actual
+
+- name: assert install reboot hotfix
+ assert:
+ that:
+ - install_reboot_hotfix is changed
+ - install_reboot_hotfix.kb == test_win_hotfix_reboot_kb
+ - install_reboot_hotfix.identifier == test_win_hotfix_reboot_identifier
+ - install_reboot_hotfix.reboot_required == True
+ - install_hotfix_reboot_actual.rc == 0
+
+- name: run install reboot again before rebooting
+ win_hotfix:
+ source: '{{test_win_hotfix_path}}\reboot.msu'
+ state: present
+ register: install_before_rebooting
+
+- name: assert install reboot again before rebooting
+ assert:
+ that:
+ - install_before_rebooting is not changed
+ - install_before_rebooting.reboot_required == True
+
+- ansible.windows.win_reboot:
+
+- name: install reboot hotfix again
+ win_hotfix:
+ hotfix_identifier: '{{test_win_hotfix_reboot_identifier}}'
+ source: '{{test_win_hotfix_path}}\reboot.msu'
+ state: present
+ register: install_reboot_hotfix_again
+
+- name: assert install reboot hotfix again
+ assert:
+ that:
+ - install_reboot_hotfix_again is not changed
+ - install_reboot_hotfix_again.reboot_required == False
+
+- name: uninstall hotfix with kb check
+ win_hotfix:
+ hotfix_kb: '{{test_win_hotfix_reboot_kb}}'
+ state: absent
+ register: uninstall_hotfix_kb_check
+ check_mode: yes
+
+- name: get result of uninstall hotfix with kb check
+ ansible.windows.win_command: powershell.exe Get-Hotfix -Id {{test_win_hotfix_reboot_kb}}
+ register: uninstall_hotfix_kb_actual_check
+
+- name: assert uninstall hotfix with kb check
+ assert:
+ that:
+ - uninstall_hotfix_kb_check is changed
+ - uninstall_hotfix_kb_check.kb == test_win_hotfix_reboot_kb
+ - uninstall_hotfix_kb_check.identifier == test_win_hotfix_reboot_identifier
+ - uninstall_hotfix_kb_check.reboot_required == False
+ - uninstall_hotfix_kb_actual_check.rc == 0
+
+- name: uninstall hotfix with kb
+ win_hotfix:
+ hotfix_kb: '{{test_win_hotfix_reboot_kb}}'
+ state: absent
+ register: uninstall_hotfix_kb
+
+- name: get result of uninstall hotfix with kb
+ ansible.windows.win_command: powershell.exe Get-Hotfix -Id {{test_win_hotfix_kb}}
+ register: uninstall_hotfix_kb_actual
+ ignore_errors: True
+
+- name: assert uninstall hotfix with kb
+ assert:
+ that:
+ - uninstall_hotfix_kb is changed
+ - uninstall_hotfix_kb.kb == test_win_hotfix_reboot_kb
+ - uninstall_hotfix_kb.identifier == test_win_hotfix_reboot_identifier
+ - uninstall_hotfix_kb.reboot_required == True
+ - uninstall_hotfix_kb_actual.rc != 0
+
+- ansible.windows.win_reboot:
+
+- name: uninstall hotfix with kb again
+ win_hotfix:
+ hotfix_kb: '{{test_win_hotfix_reboot_kb}}'
+ state: absent
+ register: uninstall_hotfix_kb_again
+
+- name: assert uninstall hotfix with kb again
+ assert:
+ that:
+ - uninstall_hotfix_kb_again is not changed
+ - uninstall_hotfix_kb_again.reboot_required == False
+
+- name: remove test staging folder
+ ansible.windows.win_file:
+ path: '{{test_win_hotfix_path}}'
+ state: absent
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_http_proxy/aliases b/ansible_collections/community/windows/tests/integration/targets/win_http_proxy/aliases
new file mode 100644
index 000000000..4cd27b3cb
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_http_proxy/aliases
@@ -0,0 +1 @@
+shippable/windows/group1
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_http_proxy/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_http_proxy/tasks/main.yml
new file mode 100644
index 000000000..5da9aa7fe
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_http_proxy/tasks/main.yml
@@ -0,0 +1,14 @@
+---
+- name: make sure we start the tests with no proxy set
+ win_http_proxy:
+
+- block:
+ - name: run tests
+ include_tasks: tests.yml
+
+ always:
+ - name: remove any explicit proxy settings
+ win_http_proxy:
+
+ - name: reset WinINet proxy settings
+ win_inet_proxy:
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_http_proxy/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_http_proxy/tasks/tests.yml
new file mode 100644
index 000000000..04a763d08
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_http_proxy/tasks/tests.yml
@@ -0,0 +1,265 @@
+---
+- name: ensure we fail when proxy is not set with bypass
+ win_http_proxy:
+ bypass: abc
+ register: fail_bypass
+ failed_when: 'fail_bypass.msg != "missing parameter(s) required by ''bypass'': proxy"'
+
+- name: ensure we fail when proxy and source is set
+ win_http_proxy:
+ proxy: proxy
+ source: ie
+ register: fail_source
+ failed_when: 'fail_source.msg != "parameters are mutually exclusive: proxy, source"'
+
+- name: ensure we fail if an invalid protocol is specified
+ win_http_proxy:
+ proxy:
+ fail1: fail
+ fail2: fail
+ register: fail_protocol
+ failed_when: 'fail_protocol.msg != "Invalid keys found in proxy: fail1, fail2. Valid keys are http, https, ftp, socks."'
+
+# WinHTTP does not validate on set, this ensures the module checks and revert any failed attempts at setting the proxy
+# FIXME: Only certain hosts seem to have a strict winhttp definition, we can't run this in CI for now
+#- name: ensure we fail if invalid value is set
+# win_http_proxy:
+# proxy: fake=proxy
+# register: fail_invalid
+# failed_when: fail_invalid.msg != "Unknown error when trying to set proxy 'fake=proxy' or bypass ''"
+#
+#- name: check proxy is still set to Direct access
+# ansible.windows.win_command: netsh winhttp show proxy
+# register: fail_invalid_actual
+# failed_when: fail_invalid_actual.stdout_lines[3]|trim != "Direct access (no proxy server)."
+
+- name: set a proxy using a string (check)
+ win_http_proxy:
+ proxy: proxyhost
+ register: proxy_str_check
+ check_mode: True
+
+- name: get result of set a proxy using a string (check)
+ ansible.windows.win_command: netsh winhttp show proxy
+ register: proxy_str_actual_check
+
+- name: assert set a proxy using a string (check)
+ assert:
+ that:
+ - proxy_str_check is changed
+ - proxy_str_actual_check.stdout_lines[3]|trim == "Direct access (no proxy server)."
+
+- name: set a proxy using a string
+ win_http_proxy:
+ proxy: proxyhost
+ register: proxy_str
+
+- name: get result of set a proxy using a string
+ ansible.windows.win_command: netsh winhttp show proxy
+ register: proxy_str_actual
+
+- name: assert set a proxy using a string
+ assert:
+ that:
+ - proxy_str is changed
+ - 'proxy_str_actual.stdout_lines[3]|trim == "Proxy Server(s) : proxyhost"'
+ - 'proxy_str_actual.stdout_lines[4]|trim == "Bypass List : (none)"'
+
+- name: set a proxy using a string (idempotent)
+ win_http_proxy:
+ proxy: proxyhost
+ register: proxy_str_again
+
+- name: assert set a proxy using a string (idempotent)
+ assert:
+ that:
+ - not proxy_str_again is changed
+
+- name: change a proxy and set bypass (check)
+ win_http_proxy:
+ proxy: proxyhost:8080
+ bypass:
+ - abc
+ - def
+ - <local>
+ register: change_proxy_check
+ check_mode: True
+
+- name: get result of change a proxy and set bypass (check)
+ ansible.windows.win_command: netsh winhttp show proxy
+ register: change_proxy_actual_check
+
+- name: assert change a proxy and set bypass (check)
+ assert:
+ that:
+ - change_proxy_check is changed
+ - 'change_proxy_actual_check.stdout_lines[3]|trim == "Proxy Server(s) : proxyhost"'
+ - 'change_proxy_actual_check.stdout_lines[4]|trim == "Bypass List : (none)"'
+
+- name: change a proxy and set bypass
+ win_http_proxy:
+ proxy: proxyhost:8080
+ bypass:
+ - abc
+ - def
+ - <local>
+ register: change_proxy
+
+- name: get result of change a proxy and set bypass
+ ansible.windows.win_command: netsh winhttp show proxy
+ register: change_proxy_actual
+
+- name: assert change a proxy and set bypass
+ assert:
+ that:
+ - change_proxy is changed
+ - 'change_proxy_actual.stdout_lines[3]|trim == "Proxy Server(s) : proxyhost:8080"'
+ - 'change_proxy_actual.stdout_lines[4]|trim == "Bypass List : abc;def;<local>"'
+
+- name: change a proxy and set bypass (idempotent)
+ win_http_proxy:
+ proxy: proxyhost:8080
+ bypass: abc,def,<local>
+ register: change_proxy_again
+
+- name: assert change a proxy and set bypass (idempotent)
+ assert:
+ that:
+ - not change_proxy_again is changed
+
+- name: change bypass list
+ win_http_proxy:
+ proxy: proxyhost:8080
+ bypass:
+ - abc
+ - <-loopback>
+ register: change_bypass
+
+- name: get result of change bypass list
+ ansible.windows.win_command: netsh winhttp show proxy
+ register: change_bypass_actual
+
+- name: assert change bypass list
+ assert:
+ that:
+ - change_bypass is changed
+ - 'change_bypass_actual.stdout_lines[3]|trim == "Proxy Server(s) : proxyhost:8080"'
+ - 'change_bypass_actual.stdout_lines[4]|trim == "Bypass List : abc;<-loopback>"'
+
+- name: remove proxy without options (check)
+ win_http_proxy:
+ register: remove_proxy_check
+ check_mode: yes
+
+- name: get result of remove proxy without options (check)
+ ansible.windows.win_command: netsh winhttp show proxy
+ register: remove_proxy_actual_check
+
+- name: assert remove proxy without options (check)
+ assert:
+ that:
+ - remove_proxy_check is changed
+ - 'remove_proxy_actual_check.stdout_lines[3]|trim == "Proxy Server(s) : proxyhost:8080"'
+ - 'remove_proxy_actual_check.stdout_lines[4]|trim == "Bypass List : abc;<-loopback>"'
+
+- name: remove proxy without options
+ win_http_proxy:
+ register: remove_proxy
+
+- name: get result of remove proxy without options
+ ansible.windows.win_command: netsh winhttp show proxy
+ register: remove_proxy_actual
+
+- name: assert remove proxy without options
+ assert:
+ that:
+ - remove_proxy is changed
+ - remove_proxy_actual.stdout_lines[3]|trim == "Direct access (no proxy server)."
+
+- name: remove proxy without options (idempotent)
+ win_http_proxy:
+ register: remove_proxy_again
+
+- name: assert remove proxy without options (idempotent)
+ assert:
+ that:
+ - not remove_proxy_again is changed
+
+- name: set proxy with dictionary
+ win_http_proxy:
+ proxy:
+ http: proxy:8080
+ https: proxy:8443
+ ftp: proxy:821
+ socks: proxy:888
+ register: set_dict
+
+- name: get result of set proxy with dictionary
+ ansible.windows.win_command: netsh winhttp show proxy
+ register: set_dict_actual
+
+- name: assert set proxy with dictionary
+ assert:
+ that:
+ - set_dict is changed
+ - 'set_dict_actual.stdout_lines[3]|trim == "Proxy Server(s) : http=proxy:8080;https=proxy:8443;ftp=proxy:821;socks=proxy:888"'
+ - 'set_dict_actual.stdout_lines[4]|trim == "Bypass List : (none)"'
+
+- name: set proxy protocol with str
+ win_http_proxy:
+ proxy: http=proxy:8080;https=proxy:8443;ftp=proxy:821;socks=proxy:888
+ register: set_str_protocol
+
+- name: assert set proxy protocol with str
+ assert:
+ that:
+ - not set_str_protocol is changed
+
+- name: remove proxy with empty string
+ win_http_proxy:
+ proxy: ''
+ register: remove_empty_str
+
+- name: get result of remove proxy with empty string
+ ansible.windows.win_command: netsh winhttp show proxy
+ register: remove_empty_str_actual
+
+- name: assert remove proxy with empty string
+ assert:
+ that:
+ - remove_empty_str is changed
+ - remove_empty_str_actual.stdout_lines[3]|trim == "Direct access (no proxy server)."
+
+- name: set explicit proxy for WinINet
+ win_inet_proxy:
+ proxy: proxyhost:8080
+ bypass:
+ - abc
+ - def
+ - <local>
+
+- name: import proxy from IE
+ win_http_proxy:
+ source: ie
+ register: import_ie
+
+- name: get result of import proxy from IE
+ ansible.windows.win_command: netsh winhttp show proxy
+ register: import_ie_actual
+
+- name: assert import proxy from IE
+ assert:
+ that:
+ - import_ie is changed
+ - 'import_ie_actual.stdout_lines[3]|trim == "Proxy Server(s) : proxyhost:8080"'
+ - 'import_ie_actual.stdout_lines[4]|trim == "Bypass List : abc;def;<local>"'
+
+- name: import proxy from IE (idempotent)
+ win_http_proxy:
+ source: ie
+ register: import_ie_again
+
+- name: assert import proxy from IE (idempotent)
+ assert:
+ that:
+ - not import_ie_again is changed
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_iis_virtualdirectory/aliases b/ansible_collections/community/windows/tests/integration/targets/win_iis_virtualdirectory/aliases
new file mode 100644
index 000000000..de2313a6a
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_iis_virtualdirectory/aliases
@@ -0,0 +1 @@
+shippable/windows/group4 \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_iis_virtualdirectory/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_iis_virtualdirectory/defaults/main.yml
new file mode 100644
index 000000000..b9dfc1971
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_iis_virtualdirectory/defaults/main.yml
@@ -0,0 +1,10 @@
+---
+
+test_vdir_name: testvdir
+test_physical_path: "{{ remote_tmp_dir }}"
+
+test_site_name: 'Test Site'
+test_app_name: 'testapp'
+
+test_user: testuser
+test_password: testpass \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_iis_virtualdirectory/meta/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_iis_virtualdirectory/meta/main.yml
new file mode 100644
index 000000000..e3dd5fb10
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_iis_virtualdirectory/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+- setup_remote_tmp_dir
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_iis_virtualdirectory/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_iis_virtualdirectory/tasks/main.yml
new file mode 100644
index 000000000..3374cbb68
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_iis_virtualdirectory/tasks/main.yml
@@ -0,0 +1,90 @@
+---
+- name: check if we can run the tests
+ ansible.windows.win_shell: |
+ $osVersion = [Version](Get-Item -LiteralPath "$env:SystemRoot\System32\kernel32.dll").VersionInfo.ProductVersion
+ $osVersion -ge [Version]"6.2"
+ register: run_test
+ changed_when: False
+
+- name: Run on Server 2012 and higher
+ when: run_test.stdout | trim | bool
+ block:
+ - name: ensure IIS features are installed
+ ansible.windows.win_feature:
+ name: Web-Server
+ state: present
+ include_management_tools: True
+ register: feature_install
+
+ - name: reboot after feature install
+ ansible.windows.win_reboot:
+ when: feature_install.reboot_required
+
+ # may be possible that copy corrupts the file
+ - name: Get iis configuration checksum
+ ansible.windows.win_stat:
+ path: C:\Windows\System32\inetsrv\config\applicationHost.config
+ checksum_algorithm: sha1
+ register: stat_result
+
+ - name: take a copy of the original iis configuration
+ ansible.windows.win_copy:
+ src: C:\Windows\System32\inetsrv\config\applicationHost.config
+ dest: '{{ remote_tmp_dir }}\applicationHost.config'
+ remote_src: yes
+ register: copy_result
+
+ - assert:
+ that:
+ - "stat_result.stat.checksum == copy_result.checksum"
+
+ # Tests
+ - name: run tests on hosts that support it
+ include_tasks: tests.yml
+
+ always:
+ # Cleanup
+ - name: remove test virtual directory
+ win_iis_virtualdirectory:
+ state: absent
+ site: "{{ test_site_name }}"
+ name: "{{ test_vdir_name }}"
+
+ - name: remove test application
+ win_iis_webapplication:
+ name: "{{ test_app_name }}"
+ site: "{{ test_site_name }}"
+ state: absent
+
+ - name: remove test site
+ win_iis_website:
+ name: "{{ test_site_name }}"
+ state: absent
+
+ - name: delete test application temporary directory
+ win_file:
+ path: "{{ test_app_tmp_dir.path }}"
+ state: absent
+
+ - name: restore iis configuration
+ ansible.windows.win_copy:
+ src: '{{ remote_tmp_dir }}\applicationHost.config'
+ dest: C:\Windows\System32\inetsrv\config\applicationHost.config
+ remote_src: yes
+ register: copy_result
+
+ - assert:
+ that:
+ - "stat_result.stat.checksum == copy_result.checksum"
+
+ - name: remove IIS feature if it was installed
+ ansible.windows.win_feature:
+ name: Web-Server
+ state: absent
+ include_management_tools: True
+ when: feature_install is changed
+ register: feature_uninstall
+
+ - name: reboot after removing IIS features
+ ansible.windows.win_reboot:
+ when: feature_uninstall.reboot_required | default(False)
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_iis_virtualdirectory/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_iis_virtualdirectory/tasks/tests.yml
new file mode 100644
index 000000000..e98271b2e
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_iis_virtualdirectory/tasks/tests.yml
@@ -0,0 +1,111 @@
+---
+- name: test site exists, but stopped in case of duplicate web binding
+ win_iis_website:
+ name: "{{ test_site_name }}"
+ state: stopped
+ physical_path: 'C:\inetpub\wwwroot'
+
+- name: test virtual directory is absent (baseline)
+ win_iis_virtualdirectory:
+ state: absent
+ site: "{{ test_site_name }}"
+ name: "{{ test_vdir_name }}"
+
+- name: create test virtual directory
+ win_iis_virtualdirectory:
+ state: present
+ site: "{{ test_site_name }}"
+ name: "{{ test_vdir_name }}"
+ physical_path: "{{ test_physical_path }}"
+ register: result
+
+- assert:
+ that:
+ - 'result.changed == true'
+ - 'result.directory.PhysicalPath == test_physical_path'
+
+- name: create test virtual directory (idempotent)
+ win_iis_virtualdirectory:
+ state: present
+ site: "{{ test_site_name }}"
+ name: "{{ test_vdir_name }}"
+ physical_path: "{{ test_physical_path }}"
+ register: result
+
+- assert:
+ that:
+ - 'result.changed == false'
+ - 'result.directory.PhysicalPath == test_physical_path'
+
+- name: set test virtual directory credentials
+ win_iis_virtualdirectory:
+ state: present
+ site: "{{ test_site_name }}"
+ name: "{{ test_vdir_name }}"
+ connect_as: specific_user
+ username: "{{ test_user }}"
+ password: "{{ test_password }}"
+ register: result
+
+- assert:
+ that:
+ - 'result.changed == true'
+ - 'result.directory.PhysicalPath == test_physical_path'
+
+- name: set test virtual directory credentials (idempotent)
+ win_iis_virtualdirectory:
+ state: present
+ site: "{{ test_site_name }}"
+ name: "{{ test_vdir_name }}"
+ connect_as: specific_user
+ username: "{{ test_user }}"
+ password: "{{ test_password }}"
+ register: result
+
+- assert:
+ that:
+ - 'result.changed == false'
+ - 'result.directory.PhysicalPath == test_physical_path'
+
+- name: create test application temporary directory
+ ansible.windows.win_tempfile:
+ suffix: ".{{ test_app_name }}"
+ state: directory
+ register: test_app_tmp_dir
+
+- name: create new test application
+ win_iis_webapplication:
+ name: "{{ test_app_name }}"
+ site: "{{ test_site_name }}"
+ physical_path: "{{ test_app_tmp_dir.path }}"
+ state: present
+
+- name: create virtual directory and use pass through authentication
+ win_iis_virtualdirectory:
+ state: present
+ site: "{{ test_site_name }}"
+ name: "{{ test_vdir_name }}"
+ physical_path: "{{ test_physical_path }}"
+ connect_as: pass_through
+ application: "{{ test_app_name }}"
+ register: result
+
+- assert:
+ that:
+ - 'result.changed == true'
+ - 'result.directory.PhysicalPath == test_physical_path'
+
+- name: create virtual directory and use pass through authentication (idempotent)
+ win_iis_virtualdirectory:
+ state: present
+ site: "{{ test_site_name }}"
+ name: "{{ test_vdir_name }}"
+ physical_path: "{{ test_physical_path }}"
+ connect_as: pass_through
+ application: "{{ test_app_name }}"
+ register: result
+
+- assert:
+ that:
+ - 'result.changed == false'
+ - 'result.directory.PhysicalPath == test_physical_path' \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_iis_webapplication/aliases b/ansible_collections/community/windows/tests/integration/targets/win_iis_webapplication/aliases
new file mode 100644
index 000000000..54a5923a5
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_iis_webapplication/aliases
@@ -0,0 +1,2 @@
+shippable/windows/group4
+unstable # Random IIS configuration errors \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_iis_webapplication/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_iis_webapplication/defaults/main.yml
new file mode 100644
index 000000000..e5a582dee
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_iis_webapplication/defaults/main.yml
@@ -0,0 +1,11 @@
+---
+
+test_app_name: TestApp
+
+test_site_name: 'Test Site'
+
+test_user: testuser
+test_password: testpass
+
+test_physical_path: "{{ remote_tmp_dir }}"
+test_apppool: 'testapppool'
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_iis_webapplication/meta/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_iis_webapplication/meta/main.yml
new file mode 100644
index 000000000..e3dd5fb10
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_iis_webapplication/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+- setup_remote_tmp_dir
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_iis_webapplication/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_iis_webapplication/tasks/main.yml
new file mode 100644
index 000000000..64b022b6a
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_iis_webapplication/tasks/main.yml
@@ -0,0 +1,84 @@
+---
+- name: check if we can run the tests
+ ansible.windows.win_shell: |
+ $osVersion = [Version](Get-Item -LiteralPath "$env:SystemRoot\System32\kernel32.dll").VersionInfo.ProductVersion
+ $osVersion -ge [Version]"6.2"
+ register: run_test
+ changed_when: False
+
+- name: Run on Server 2012 and higher
+ when: run_test.stdout | trim | bool
+ block:
+ - name: ensure IIS features are installed
+ ansible.windows.win_feature:
+ name: Web-Server
+ state: present
+ include_management_tools: True
+ register: feature_install
+
+ - name: reboot after feature install
+ ansible.windows.win_reboot:
+ when: feature_install.reboot_required
+
+ # may be possible that copy corrupts the file
+ - name: Get iis configuration checksum
+ ansible.windows.win_stat:
+ path: C:\Windows\System32\inetsrv\config\applicationHost.config
+ checksum_algorithm: sha1
+ register: stat_result
+
+ - name: take a copy of the original iis configuration
+ ansible.windows.win_copy:
+ src: C:\Windows\System32\inetsrv\config\applicationHost.config
+ dest: '{{ remote_tmp_dir }}\applicationHost.config'
+ remote_src: yes
+ register: copy_result
+
+ - assert:
+ that:
+ - "stat_result.stat.checksum == copy_result.checksum"
+
+ # Tests
+ - name: run tests on hosts that support it
+ include_tasks: tests.yml
+
+ always:
+ # Cleanup
+ - name: remove test application
+ win_iis_webapplication:
+ state: absent
+ site: "{{ test_site_name }}"
+ name: "{{ test_app_name }}"
+
+ - name: remove test application pool
+ win_iis_webapppool:
+ name: "{{ test_apppool }}"
+ state: absent
+
+ - name: remove test site
+ win_iis_website:
+ name: "{{ test_site_name }}"
+ state: absent
+
+ - name: restore iis configuration
+ ansible.windows.win_copy:
+ src: '{{ remote_tmp_dir }}\applicationHost.config'
+ dest: C:\Windows\System32\inetsrv\config\applicationHost.config
+ remote_src: yes
+ register: copy_result
+
+ - assert:
+ that:
+ - "stat_result.stat.checksum == copy_result.checksum"
+
+ - name: remove IIS feature if it was installed
+ ansible.windows.win_feature:
+ name: Web-Server
+ state: absent
+ include_management_tools: True
+ when: feature_install is changed
+ register: feature_uninstall
+
+ - name: reboot after removing IIS features
+ ansible.windows.win_reboot:
+ when: feature_uninstall.reboot_required | default(False)
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_iis_webapplication/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_iis_webapplication/tasks/tests.yml
new file mode 100644
index 000000000..135cccfec
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_iis_webapplication/tasks/tests.yml
@@ -0,0 +1,91 @@
+---
+- name: test site exists, but stopped in case of duplicate web binding
+ win_iis_website:
+ name: "{{ test_site_name }}"
+ state: stopped
+ physical_path: 'C:\inetpub\wwwroot'
+
+- name: test app is absent (baseline)
+ win_iis_webapplication:
+ state: absent
+ site: "{{ test_site_name }}"
+ name: "{{ test_app_name }}"
+
+- name: create test app
+ win_iis_webapplication:
+ state: present
+ site: "{{ test_site_name }}"
+ name: "{{ test_app_name }}"
+ physical_path: "{{ test_physical_path }}"
+ register: result
+
+- assert:
+ that:
+ - 'result.changed == true'
+ - 'result.physical_path == test_physical_path'
+
+- name: create test app (idempotent)
+ win_iis_webapplication:
+ state: present
+ site: "{{ test_site_name }}"
+ name: "{{ test_app_name }}"
+ physical_path: "{{ test_physical_path }}"
+ register: result
+
+- assert:
+ that:
+ - 'result.changed == false'
+ - 'result.physical_path == test_physical_path'
+
+- name: set test app credentials
+ win_iis_webapplication:
+ state: present
+ site: "{{ test_site_name }}"
+ name: "{{ test_app_name }}"
+ connect_as: specific_user
+ username: "{{ test_user }}"
+ password: "{{ test_password }}"
+ register: result
+
+- assert:
+ that:
+ - 'result.changed == true'
+ - 'result.physical_path == test_physical_path'
+ - "result.connect_as == 'specific_user'"
+
+- name: set test app credentials (idempotent)
+ win_iis_webapplication:
+ state: present
+ site: "{{ test_site_name }}"
+ name: "{{ test_app_name }}"
+ connect_as: specific_user
+ username: "{{ test_user }}"
+ password: "{{ test_password }}"
+ register: result
+
+- assert:
+ that:
+ - 'result.changed == false'
+ - 'result.physical_path == test_physical_path'
+ - "result.connect_as == 'specific_user'"
+
+- name: create new test application pool
+ win_iis_webapppool:
+ name: "{{ test_apppool }}"
+ state: present
+
+- name: change app pool and use pass through authentication
+ win_iis_webapplication:
+ state: present
+ site: "{{ test_site_name }}"
+ name: "{{ test_app_name }}"
+ connect_as: pass_through
+ application_pool: "{{ test_apppool }}"
+ register: result
+
+- assert:
+ that:
+ - 'result.changed == true'
+ - 'result.physical_path == test_physical_path'
+ - "result.connect_as == 'pass_through'"
+ - "result.application_pool == test_apppool"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_iis_webapppool/aliases b/ansible_collections/community/windows/tests/integration/targets/win_iis_webapppool/aliases
new file mode 100644
index 000000000..3cf5b97e8
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_iis_webapppool/aliases
@@ -0,0 +1 @@
+shippable/windows/group3
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_iis_webapppool/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_iis_webapppool/defaults/main.yml
new file mode 100644
index 000000000..bd0f15c99
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_iis_webapppool/defaults/main.yml
@@ -0,0 +1 @@
+test_iis_webapppool_name: TestPool \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_iis_webapppool/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_iis_webapppool/tasks/main.yml
new file mode 100644
index 000000000..f00fbc70a
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_iis_webapppool/tasks/main.yml
@@ -0,0 +1,43 @@
+---
+# Cannot use win_feature to install IIS on Server 2008.
+# Run a brief check and skip hosts that don't support
+# that operation
+- name: check if win_feature will work on test host
+ ansible.windows.win_command: powershell.exe "Get-WindowsFeature"
+ register: module_available
+ failed_when: False
+
+# Run actual tests
+- block:
+ - name: ensure IIS features are installed
+ ansible.windows.win_feature:
+ name: Web-Server
+ state: present
+ include_management_tools: True
+ register: feature_install
+
+ - name: reboot after feature install
+ ansible.windows.win_reboot:
+ when: feature_install.reboot_required
+
+ - name: set version of IIS for tests
+ win_file_version:
+ path: C:\Windows\System32\inetsrv\w3wp.exe
+ register: iis_version
+
+ - name: ensure test pool is deleted as a baseline
+ win_iis_webapppool:
+ name: '{{test_iis_webapppool_name}}'
+ state: absent
+
+ # Tests
+ - name: run tests on hosts that support it
+ include_tasks: tests.yml
+
+ always:
+ # Cleanup
+ - name: ensure test pool is deleted
+ win_iis_webapppool:
+ name: '{{test_iis_webapppool_name}}'
+ state: absent
+ when: module_available.rc == 0
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_iis_webapppool/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_iis_webapppool/tasks/tests.yml
new file mode 100644
index 000000000..ff28a6990
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_iis_webapppool/tasks/tests.yml
@@ -0,0 +1,424 @@
+---
+- name: create default pool check
+ win_iis_webapppool:
+ name: '{{test_iis_webapppool_name}}'
+ state: started
+ register: create_default_check
+ check_mode: yes
+
+- name: get actual of create default pool check
+ ansible.windows.win_command: powershell.exe "Import-Module WebAdministration; Get-Item -Path IIS:\AppPools\{{test_iis_webapppool_name}}"
+ register: create_default_actual_check
+ failed_when: False
+
+- name: assert create default pool check
+ assert:
+ that:
+ - create_default_check is changed
+ - create_default_actual_check.rc == 1
+
+- name: create default pool
+ win_iis_webapppool:
+ name: '{{test_iis_webapppool_name}}'
+ state: present
+ register: create_default
+
+- name: get actual of create default pool
+ ansible.windows.win_command: powershell.exe "Import-Module WebAdministration; Get-Item -Path IIS:\AppPools\{{test_iis_webapppool_name}}"
+ register: create_default_actual
+ failed_when: False
+
+- name: assert create default pool
+ assert:
+ that:
+ - create_default is changed
+ - create_default.info.attributes.name == test_iis_webapppool_name
+ - create_default.info.attributes.startMode == 'OnDemand'
+ - create_default.info.attributes.state == 'Started'
+ - create_default_actual.rc == 0
+
+- name: change attributes of pool check
+ win_iis_webapppool:
+ name: '{{test_iis_webapppool_name}}'
+ state: present
+ attributes:
+ managedPipelineMode: 1 # Using an enum value
+ cpu.limit: 95 # Nested values
+ processModel.identityType: LocalSystem # Using an enum name
+ processModel.loadUserProfile: True
+ register: change_pool_attributes_check
+ check_mode: yes
+
+- name: assert change attributes of pool check
+ assert:
+ that:
+ - change_pool_attributes_check is changed
+ - change_pool_attributes_check.info == create_default.info
+
+- name: change attributes of pool
+ win_iis_webapppool:
+ name: '{{test_iis_webapppool_name}}'
+ state: present
+ attributes:
+ managedPipelineMode: 1 # Using an enum value
+ cpu.limit: 95 # Nested values
+ processModel.identityType: LocalSystem # Using an enum name
+ processModel.loadUserProfile: True
+ test: True
+ register: change_pool_attributes
+
+- name: assert change attributes of pool
+ assert:
+ that:
+ - change_pool_attributes is changed
+ - change_pool_attributes.info.attributes.managedPipelineMode == 'Classic'
+ - change_pool_attributes.info.cpu.limit == 95
+ - change_pool_attributes.info.processModel.identityType == 'LocalSystem'
+ - change_pool_attributes.info.processModel.loadUserProfile == True
+
+- name: change attributes of pool again
+ win_iis_webapppool:
+ name: '{{test_iis_webapppool_name}}'
+ state: present
+ attributes:
+ managedPipelineMode: 1 # Using an enum value
+ cpu.limit: 95 # Nested values
+ processModel.identityType: LocalSystem # Using an enum name
+ processModel.loadUserProfile: True
+ register: change_pool_attributes_again
+
+- name: assert change attributes of pool again
+ assert:
+ that:
+ - change_pool_attributes_again is not changed
+ - change_pool_attributes_again.info == change_pool_attributes.info
+
+- name: change more complex variables check
+ win_iis_webapppool:
+ name: '{{test_iis_webapppool_name}}'
+ state: present
+ attributes:
+ queueLength: 500
+ recycling.periodicRestart.requests: 10 # Deeply nested attribute
+ recycling.periodicRestart.time: "00:00:05:00.000000" # Timespan with string
+ processModel.pingResponseTime: "00:03:00" # Timespan without days or milliseconds
+ register: change_complex_attributes_check
+ check_mode: yes
+
+- name: assert change more complex variables check
+ assert:
+ that:
+ - change_complex_attributes_check is changed
+ - change_complex_attributes_check.info == change_pool_attributes_again.info
+
+- name: change more complex variables
+ win_iis_webapppool:
+ name: '{{test_iis_webapppool_name}}'
+ state: present
+ attributes:
+ queueLength: 500
+ recycling.periodicRestart.requests: 10 # Deeply nested attribute
+ recycling.periodicRestart.time: "00:00:05:00.000000" # Timespan with string
+ processModel.pingResponseTime: "00:03:00" # Timespan without days or milliseconds
+ register: change_complex_attributes
+
+- name: assert change more complex variables
+ assert:
+ that:
+ - change_complex_attributes is changed
+ - change_complex_attributes.info.attributes.queueLength == 500
+ - change_complex_attributes.info.recycling.periodicRestart.requests == 10
+ - change_complex_attributes.info.recycling.periodicRestart.time.TotalSeconds == 300
+ - change_complex_attributes.info.processModel.pingResponseTime.TotalSeconds == 180
+
+- name: change more complex variables again
+ win_iis_webapppool:
+ name: '{{test_iis_webapppool_name}}'
+ state: present
+ attributes:
+ queueLength: 500
+ recycling.periodicRestart.requests: 10 # Deeply nested attribute
+ recycling.periodicRestart.time: "00:00:05:00.000000" # Timespan with string
+ processModel.pingResponseTime: "00:03:00" # Timespan without days or milliseconds
+ register: change_complex_attributes_again
+
+- name: assert change more complex variables again
+ assert:
+ that:
+ - change_complex_attributes_again is not changed
+ - change_complex_attributes_again.info == change_complex_attributes.info
+
+- name: stop web pool check
+ win_iis_webapppool:
+ name: '{{test_iis_webapppool_name}}'
+ state: stopped
+ register: stop_pool_check
+ check_mode: yes
+
+- name: get actual status of pool check
+ ansible.windows.win_command: powershell.exe "Import-Module WebAdministration; (Get-Item -Path IIS:\AppPools\{{test_iis_webapppool_name}}).state"
+ register: stop_pool_actual_check
+
+- name: assert stop web pool check
+ assert:
+ that:
+ - stop_pool_check is changed
+ - stop_pool_actual_check.stdout == 'Started\r\n'
+
+- name: stop web pool
+ win_iis_webapppool:
+ name: '{{test_iis_webapppool_name}}'
+ state: stopped
+ register: stop_pool
+
+- name: get actual status of pool
+ ansible.windows.win_command: powershell.exe "Import-Module WebAdministration; (Get-Item -Path IIS:\AppPools\{{test_iis_webapppool_name}}).state"
+ register: stop_pool_actual
+
+- name: assert stop web pool
+ assert:
+ that:
+ - stop_pool is changed
+ - stop_pool_actual.stdout == 'Stopped\r\n'
+
+- name: stop web pool again
+ win_iis_webapppool:
+ name: '{{test_iis_webapppool_name}}'
+ state: stopped
+ register: stop_pool_again
+
+- name: get actual status of pool again
+ ansible.windows.win_command: powershell.exe "Import-Module WebAdministration; (Get-Item -Path IIS:\AppPools\{{test_iis_webapppool_name}}).state"
+ register: stop_pool_actual_again
+
+- name: assert stop web pool again
+ assert:
+ that:
+ - stop_pool_again is not changed
+ - stop_pool_actual_again.stdout == 'Stopped\r\n'
+
+- name: start web pool check
+ win_iis_webapppool:
+ name: '{{test_iis_webapppool_name}}'
+ state: started
+ register: start_pool_check
+ check_mode: yes
+
+- name: get actual status of pool check
+ ansible.windows.win_command: powershell.exe "Import-Module WebAdministration; (Get-Item -Path IIS:\AppPools\{{test_iis_webapppool_name}}).state"
+ register: start_pool_actual_check
+
+- name: assert start web pool check
+ assert:
+ that:
+ - start_pool_check is changed
+ - start_pool_actual_check.stdout == 'Stopped\r\n'
+
+- name: start web pool
+ win_iis_webapppool:
+ name: '{{test_iis_webapppool_name}}'
+ state: started
+ register: start_pool
+
+- name: get actual status of pool
+ ansible.windows.win_command: powershell.exe "Import-Module WebAdministration; (Get-Item -Path IIS:\AppPools\{{test_iis_webapppool_name}}).state"
+ register: start_pool_actual
+
+- name: assert start web pool
+ assert:
+ that:
+ - start_pool is changed
+ - start_pool_actual.stdout == 'Started\r\n'
+
+- name: start web pool again
+ win_iis_webapppool:
+ name: '{{test_iis_webapppool_name}}'
+ state: started
+ register: start_pool_again
+
+- name: get actual status of pool again
+ ansible.windows.win_command: powershell.exe "Import-Module WebAdministration; (Get-Item -Path IIS:\AppPools\{{test_iis_webapppool_name}}).state"
+ register: start_pool_actual_again
+
+- name: assert start web pool again
+ assert:
+ that:
+ - start_pool_again is not changed
+ - start_pool_actual_again.stdout == 'Started\r\n'
+
+- name: restart web pool
+ win_iis_webapppool:
+ name: '{{test_iis_webapppool_name}}'
+ state: restarted
+ register: restart_pool
+
+- name: get actual status of pool
+ ansible.windows.win_command: powershell.exe "Import-Module WebAdministration; (Get-Item -Path IIS:\AppPools\{{test_iis_webapppool_name}}).state"
+ register: restart_pool_actual
+
+- name: assert restart web pool
+ assert:
+ that:
+ - restart_pool is changed
+ - restart_pool_actual.stdout == 'Started\r\n'
+
+- name: stop pool before restart on stop test
+ win_iis_webapppool:
+ name: '{{test_iis_webapppool_name}}'
+ state: stopped
+
+- name: restart from stopped web pool check
+ win_iis_webapppool:
+ name: '{{test_iis_webapppool_name}}'
+ state: restarted
+ register: restart_from_stop_pool_check
+ check_mode: yes
+
+- name: get actual status of pool check
+ ansible.windows.win_command: powershell.exe "Import-Module WebAdministration; (Get-Item -Path IIS:\AppPools\{{test_iis_webapppool_name}}).state"
+ register: restart_from_stop_pool_actual_check
+
+- name: assert restart from stopped web pool check
+ assert:
+ that:
+ - restart_from_stop_pool_check is changed
+ - restart_from_stop_pool_actual_check.stdout == 'Stopped\r\n'
+
+- name: restart from stopped web pool
+ win_iis_webapppool:
+ name: '{{test_iis_webapppool_name}}'
+ state: restarted
+ register: restart_from_stop_pool
+
+- name: get actual status of pool
+ ansible.windows.win_command: powershell.exe "Import-Module WebAdministration; (Get-Item -Path IIS:\AppPools\{{test_iis_webapppool_name}}).state"
+ register: restart_from_stop_pool_actual
+
+- name: assert restart from stopped web pool
+ assert:
+ that:
+ - restart_from_stop_pool is changed
+ - restart_from_stop_pool_actual.stdout == 'Started\r\n'
+
+- name: set web pool attribute that is a collection (check mode)
+ win_iis_webapppool:
+ name: '{{test_iis_webapppool_name}}'
+ state: present
+ attributes:
+ recycling.periodicRestart.schedule: "00:10:00,10:10:00"
+ register: collection_change_check
+ check_mode: yes
+
+- name: get result of set web pool attribute that is a collection (check mode)
+ ansible.windows.win_shell: |
+ Import-Module WebAdministration
+ (Get-ItemProperty -Path "IIS:\AppPools\{{test_iis_webapppool_name}}" -Name recycling.periodicRestart.schedule).Collection | ForEach-Object { $_.value.ToString() }
+ register: collection_change_result_check
+
+- name: assert results of set web pool attribute that is a collection (check mode)
+ assert:
+ that:
+ - collection_change_check is changed
+ - collection_change_result_check.stdout == ""
+
+- name: set web pool attribute that is a collection
+ win_iis_webapppool:
+ name: '{{test_iis_webapppool_name}}'
+ state: present
+ attributes:
+ recycling.periodicRestart.schedule: "00:10:00,10:10:00"
+ register: collection_change
+
+- name: get result of set web pool attribute that is a collection
+ ansible.windows.win_shell: |
+ Import-Module WebAdministration
+ (Get-ItemProperty -Path "IIS:\AppPools\{{test_iis_webapppool_name}}" -Name recycling.periodicRestart.schedule).Collection | ForEach-Object { $_.value.ToString() }
+ register: collection_change_result
+
+- name: assert results of set web pool attribute that is a collection
+ assert:
+ that:
+ - collection_change is changed
+ - collection_change_result.stdout_lines == [ "00:10:00", "10:10:00" ]
+
+- name: set web pool attribute that is a collection (idempotent)
+ win_iis_webapppool:
+ name: '{{test_iis_webapppool_name}}'
+ state: present
+ attributes:
+ recycling.periodicRestart.schedule: [ "00:10:00", "10:10:00" ]
+ register: collection_change_again
+
+- name: assert results of set web pool attribute that is a collection (idempotent)
+ assert:
+ that:
+ - collection_change_again is not changed
+
+# The following tests are only for IIS versions 8.0 or newer
+- block:
+ - name: delete test pool
+ win_iis_webapppool:
+ name: '{{test_iis_webapppool_name}}'
+ state: absent
+
+ - name: create test pool
+ win_iis_webapppool:
+ name: '{{test_iis_webapppool_name}}'
+ state: present
+ register: iis_attributes_blank
+
+ - name: change attributes for newer IIS version check
+ win_iis_webapppool:
+ name: '{{test_iis_webapppool_name}}'
+ state: present
+ attributes:
+ startMode: AlwaysRunning
+ processModel.identityType: SpecificUser
+ processModel.userName: '{{ansible_user}}'
+ processModel.password: '{{ansible_password}}'
+ register: iis_attributes_new_check
+ check_mode: yes
+
+ - name: assert change attributes for newer IIS version check
+ assert:
+ that:
+ - iis_attributes_new_check is changed
+ - iis_attributes_new_check.info == iis_attributes_blank.info
+
+ - name: change attributes for newer IIS version
+ win_iis_webapppool:
+ name: '{{test_iis_webapppool_name}}'
+ state: present
+ attributes:
+ startMode: AlwaysRunning
+ processModel.identityType: SpecificUser
+ processModel.userName: '{{ansible_user}}'
+ processModel.password: '{{ansible_password}}'
+ register: iis_attributes_new
+
+ - name: assert change attributes for newer IIS version
+ assert:
+ that:
+ - iis_attributes_new is changed
+ - iis_attributes_new.info.attributes.startMode == 'AlwaysRunning'
+ - iis_attributes_new.info.processModel.identityType == 'SpecificUser'
+ - iis_attributes_new.info.processModel.userName == ansible_user
+
+ - name: change attributes for newer IIS version again
+ win_iis_webapppool:
+ name: '{{test_iis_webapppool_name}}'
+ state: present
+ attributes:
+ startMode: AlwaysRunning
+ processModel.identityType: 3
+ processModel.userName: '{{ansible_user}}'
+ processModel.password: '{{ansible_password}}'
+ register: iis_attributes_new_again
+
+ - name: assert change attributes for newer IIS version again
+ assert:
+ that:
+ - iis_attributes_new_again is not changed
+ - iis_attributes_new_again.info == iis_attributes_new.info
+
+ when: iis_version.win_file_version.file_major_part|int > 7
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/aliases b/ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/aliases
new file mode 100644
index 000000000..423ce3910
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/aliases
@@ -0,0 +1 @@
+shippable/windows/group2
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/defaults/main.yml
new file mode 100644
index 000000000..13f0bc333
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/defaults/main.yml
@@ -0,0 +1,30 @@
+test_iis_site_name: default web site
+
+http_vars:
+ protocol: http
+ port: 80
+ ip: '*'
+
+http_header_vars:
+ protocol: http
+ port: 80
+ ip: '*'
+ header: test.com
+
+https_vars:
+ protocol: https
+ port: 443
+ ip: '*'
+
+https_header_vars:
+ protocol: https
+ port: 443
+ ip: '*'
+ header: test.com
+ ssl_flags: 1
+
+https_wc_vars:
+ protocol: https
+ port: 443
+ ip: '127.0.0.1'
+ header: wc.test.com
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/library/test_get_webbindings.ps1 b/ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/library/test_get_webbindings.ps1
new file mode 100644
index 000000000..f1d49f46a
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/library/test_get_webbindings.ps1
@@ -0,0 +1,106 @@
+#!powershell
+
+# Copyright: (c) 2017, Noah Sparks <nsparks@outlook.com>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#Requires -Module Ansible.ModuleUtils.Legacy
+
+$params = Parse-Args -arguments $args -supports_check_mode $true
+
+$name = Get-AnsibleParam $params -name "name" -type str -failifempty $true -aliases 'website'
+$host_header = Get-AnsibleParam $params -name "host_header" -type str
+$protocol = Get-AnsibleParam $params -name "protocol" -type str -default 'http'
+$port = Get-AnsibleParam $params -name "port" -type int -default '80'
+$ip = Get-AnsibleParam $params -name "ip" -default '*'
+
+$result = @{
+ changed = $false
+}
+function New-BindingInfo {
+ $ht = @{
+ 'bindingInformation' = $args[0].bindingInformation
+ 'ip' = $args[0].bindingInformation.split(':')[0]
+ 'port' = [int]$args[0].bindingInformation.split(':')[1]
+ 'hostheader' = $args[0].bindingInformation.split(':')[2]
+ 'isDsMapperEnabled' = $args[0].isDsMapperEnabled
+ 'protocol' = $args[0].protocol
+ 'certificateStoreName' = $args[0].certificateStoreName
+ 'certificateHash' = $args[0].certificateHash
+ }
+
+ #handle sslflag support
+ If ([version][System.Environment]::OSVersion.Version -lt [version]'6.2') {
+ $ht.sslFlags = 'not supported'
+ }
+ Else {
+ $ht.sslFlags = [int]$args[0].sslFlags
+ }
+
+ Return $ht
+}
+
+# Used instead of get-webbinding to ensure we always return a single binding
+# pass it $binding_parameters hashtable
+function Get-SingleWebBinding {
+
+ Try {
+ $site_bindings = get-webbinding -name $args[0].name
+ }
+ Catch {
+ # 2k8r2 throws this error when you run get-webbinding with no bindings in iis
+ $msg = 'Cannot process argument because the value of argument "obj" is null. Change the value of argument "obj" to a non-null value'
+ If (-not $_.Exception.Message.CompareTo($msg)) {
+ Throw $_.Exception.Message
+ }
+ Else { return }
+ }
+
+ Foreach ($binding in $site_bindings) {
+ $splits = $binding.bindingInformation -split ':'
+
+ if (
+ $args[0].protocol -eq $binding.protocol -and
+ $args[0].ipaddress -eq $splits[0] -and
+ $args[0].port -eq $splits[1] -and
+ $args[0].hostheader -eq $splits[2]
+ ) {
+ Return $binding
+ }
+ }
+}
+
+# create binding search splat
+$binding_parameters = @{
+ Name = $name
+ Protocol = $protocol
+ Port = $port
+ IPAddress = $ip
+}
+
+# insert host header to search if specified, otherwise it will return * (all bindings matching protocol/ip)
+If ($host_header) {
+ $binding_parameters.HostHeader = $host_header
+}
+Else {
+ $binding_parameters.HostHeader = [string]::Empty
+}
+
+# Get bindings matching parameters
+Try {
+ $current_bindings = Get-SingleWebBinding $binding_parameters
+}
+Catch {
+ Fail-Json -obj $result -message "Failed to retrieve bindings with Get-SingleWebBinding - $($_.Exception.Message)"
+}
+
+If ($current_bindings) {
+ Try {
+ $binding_info = New-BindingInfo $current_bindings
+ }
+ Catch {
+ Fail-Json -obj $result -message "Failed to create binding info - $($_.Exception.Message)"
+ }
+
+ $result.binding = $binding_info
+}
+exit-json -obj $result \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/tasks/failures.yml b/ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/tasks/failures.yml
new file mode 100644
index 000000000..92736fe1b
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/tasks/failures.yml
@@ -0,0 +1,70 @@
+- name: failure check define * for host header
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: present
+ host_header: '*'
+ protocol: http
+ ip: '*'
+ register: failure
+ failed_when: failure.msg != "To make or remove a catch-all binding, please omit the host_header parameter entirely rather than specify host_header *"
+
+- debug:
+ var: failure
+ verbosity: 1
+
+- block:
+ - name: get all websites from server
+ raw: powershell.exe "(get-website).name"
+ register: existing_sites
+
+ - name: ensure all sites are removed for clean testing
+ win_iis_website:
+ name: "{{ item }}"
+ state: absent
+ with_items:
+ - "{{ existing_sites.stdout_lines }}"
+
+ - name: add testremove site
+ win_iis_website:
+ name: testremove
+ state: started
+ physical_path: c:\inetpub\wwwroot
+
+ - name: add bindings to testremove
+ win_iis_webbinding:
+ name: testremove
+ ip: "{{ item.ip }}"
+ port: "{{ item.port }}"
+ with_items:
+ - {ip: 127.0.0.1, port: 80}
+ - {ip: '*', port: 80}
+
+ - name: remove ip * binding from testremove
+ win_iis_webbinding:
+ name: testremove
+ state: absent
+ port: 80
+ ip: '*'
+
+ - name: get the remaining binding from testremove
+ test_get_webbindings:
+ name: testremove
+ port: 80
+ ip: 127.0.0.1
+ register: test_result
+
+ - debug:
+ var: test_result
+ verbosity: 1
+
+ - name: assert that remove *:80 doesn't also remove 127.0.0.1:80
+ assert:
+ that:
+ - test_result.binding.ip == '127.0.0.1'
+ - test_result.binding.port == 80
+
+ always:
+ - name: remove websites
+ win_iis_website:
+ name: testremove
+ state: absent
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/tasks/http.yml b/ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/tasks/http.yml
new file mode 100644
index 000000000..34c4cc2c1
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/tasks/http.yml
@@ -0,0 +1,317 @@
+#cm add
+#changed true, check nothing present
+- name: CM add http binding no header
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: present
+ protocol: "{{ http_vars.protocol }}"
+ ip: "{{ http_vars.ip }}"
+ port: "{{ http_vars.port }}"
+ register: http_no_header
+ check_mode: yes
+
+- name: CM get binding info no header
+ test_get_webbindings:
+ name: "{{ test_iis_site_name }}"
+ protocol: "{{ http_vars.protocol }}"
+ ip: "{{ http_vars.ip }}"
+ port: "{{ http_vars.port }}"
+ register: get_http_no_header
+ changed_when: false
+
+- name: CM add http binding with header
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: present
+ host_header: "{{ http_header_vars.header }}"
+ protocol: "{{ http_header_vars.protocol }}"
+ ip: "{{ http_header_vars.ip }}"
+ port: "{{ http_header_vars.port }}"
+ register: http_header
+ check_mode: yes
+
+- name: CM get binding info header
+ test_get_webbindings:
+ name: "{{ test_iis_site_name }}"
+ host_header: "{{ http_header_vars.header }}"
+ protocol: "{{ http_header_vars.protocol }}"
+ ip: "{{ http_header_vars.ip }}"
+ port: "{{ http_header_vars.port }}"
+ register: get_http_header
+ changed_when: false
+
+- name: CM assert changed, but not added
+ assert:
+ that:
+ - http_no_header is changed
+ - http_no_header.binding_info is none
+ - get_http_no_header.binding is not defined
+ - http_header is changed
+ - http_header.binding_info is none
+ - get_http_header.binding is not defined
+
+#add
+#changed true, new bindings present
+- name: add http binding no header
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: present
+ protocol: "{{ http_vars.protocol }}"
+ ip: "{{ http_vars.ip }}"
+ port: "{{ http_vars.port }}"
+ register: http_no_header
+
+- name: get binding info no header
+ test_get_webbindings:
+ name: "{{ test_iis_site_name }}"
+ protocol: "{{ http_vars.protocol }}"
+ ip: "{{ http_vars.ip }}"
+ port: "{{ http_vars.port }}"
+ register: get_http_no_header
+ changed_when: false
+
+- name: add http binding with header
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: present
+ host_header: "{{ http_header_vars.header }}"
+ protocol: "{{ http_header_vars.protocol }}"
+ ip: "{{ http_header_vars.ip }}"
+ port: "{{ http_header_vars.port }}"
+ register: http_header
+
+- name: get binding info header
+ test_get_webbindings:
+ name: "{{ test_iis_site_name }}"
+ host_header: "{{ http_header_vars.header }}"
+ protocol: "{{ http_header_vars.protocol }}"
+ ip: "{{ http_header_vars.ip }}"
+ port: "{{ http_header_vars.port }}"
+ register: get_http_header
+ changed_when: false
+
+- name: assert changed and added
+ assert:
+ that:
+ - http_no_header is changed
+ - http_no_header.binding_info is defined
+ - http_no_header.operation_type == 'added'
+ - http_no_header.binding_info.ip == "{{ http_vars.ip }}"
+ - http_no_header.binding_info.port == {{ http_vars.port }}
+ - http_no_header.binding_info.protocol == "{{ http_vars.protocol }}"
+ - http_header is changed
+ - http_header.binding_info is defined
+ - http_header.operation_type == 'added'
+ - http_header.binding_info.ip == "{{ http_header_vars.ip }}"
+ - http_header.binding_info.port == {{ http_header_vars.port }}
+ - http_header.binding_info.protocol == "{{ http_header_vars.protocol }}"
+ - http_header.binding_info.hostheader == "{{ http_header_vars.header }}"
+
+#add idem
+#changed false
+- name: idem add http binding no header
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: present
+ protocol: "{{ http_vars.protocol }}"
+ ip: "{{ http_vars.ip }}"
+ port: "{{ http_vars.port }}"
+ register: http_no_header
+
+- name: idem add http binding with header
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: present
+ host_header: "{{ http_header_vars.header }}"
+ protocol: "{{ http_header_vars.protocol }}"
+ ip: "{{ http_header_vars.ip }}"
+ port: "{{ http_header_vars.port }}"
+ register: http_header
+
+- name: idem assert not changed
+ assert:
+ that:
+ - http_no_header is not changed
+ - http_header is not changed
+
+#modify
+#can't test modify for http, it will add a new binding instead since
+#there's no way to match existing bindings against the new parameters
+
+#cm remove
+#changed true, bindings still present
+- name: cm remove http binding no header
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: absent
+ protocol: "{{ http_vars.protocol }}"
+ ip: "{{ http_vars.ip }}"
+ port: "{{ http_vars.port }}"
+ register: http_no_header
+ check_mode: yes
+
+- name: get binding info no header
+ test_get_webbindings:
+ name: "{{ test_iis_site_name }}"
+ protocol: "{{ http_vars.protocol }}"
+ ip: "{{ http_vars.ip }}"
+ port: "{{ http_vars.port }}"
+ register: get_http_no_header
+ changed_when: false
+
+- name: cm remove http binding with header
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: absent
+ host_header: "{{ http_header_vars.header }}"
+ protocol: "{{ http_header_vars.protocol }}"
+ ip: "{{ http_header_vars.ip }}"
+ port: "{{ http_header_vars.port }}"
+ register: http_header
+ check_mode: yes
+
+- name: get binding info header
+ test_get_webbindings:
+ name: "{{ test_iis_site_name }}"
+ host_header: "{{ http_header_vars.header }}"
+ protocol: "{{ http_header_vars.protocol }}"
+ ip: "{{ http_header_vars.ip }}"
+ port: "{{ http_header_vars.port }}"
+ register: get_http_header
+ changed_when: false
+
+- name: cm remove assert changed, but still present
+ assert:
+ that:
+ - http_no_header is changed
+ - http_no_header.binding_info is defined
+ - http_no_header.operation_type == 'removed'
+ - http_no_header.binding_info.ip == "{{ http_vars.ip }}"
+ - http_no_header.binding_info.port == {{ http_vars.port }}
+ - http_no_header.binding_info.protocol == "{{ http_vars.protocol }}"
+ - get_http_no_header.binding is defined
+ - get_http_no_header.binding.ip == "{{ http_vars.ip }}"
+ - get_http_no_header.binding.port == {{ http_vars.port }}
+ - get_http_no_header.binding.protocol == "{{ http_vars.protocol }}"
+ - http_header is changed
+ - http_header.binding_info is defined
+ - http_header.operation_type == 'removed'
+ - http_header.binding_info.ip == "{{ http_header_vars.ip }}"
+ - http_header.binding_info.port == {{ http_header_vars.port }}
+ - http_header.binding_info.protocol == "{{ http_header_vars.protocol }}"
+ - http_header.binding_info.hostheader == "{{ http_header_vars.header }}"
+ - get_http_header.binding is defined
+ - get_http_header.binding.ip == "{{ http_header_vars.ip }}"
+ - get_http_header.binding.port == {{ http_header_vars.port }}
+ - get_http_header.binding.protocol == "{{ http_header_vars.protocol }}"
+ - get_http_header.binding.hostheader == "{{ http_header_vars.header }}"
+
+
+#remove
+#changed true, bindings gone
+- name: remove http binding no header
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: absent
+ protocol: "{{ http_vars.protocol }}"
+ ip: "{{ http_vars.ip }}"
+ port: "{{ http_vars.port }}"
+ register: http_no_header
+
+- name: get binding info no header
+ test_get_webbindings:
+ name: "{{ test_iis_site_name }}"
+ protocol: "{{ http_vars.protocol }}"
+ ip: "{{ http_vars.ip }}"
+ port: "{{ http_vars.port }}"
+ register: get_http_no_header
+ changed_when: false
+
+- name: remove http binding with header
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: absent
+ host_header: "{{ http_header_vars.header }}"
+ protocol: "{{ http_header_vars.protocol }}"
+ ip: "{{ http_header_vars.ip }}"
+ port: "{{ http_header_vars.port }}"
+ register: http_header
+
+- name: get binding info header
+ test_get_webbindings:
+ name: "{{ test_iis_site_name }}"
+ host_header: "{{ http_header_vars.header }}"
+ protocol: "{{ http_header_vars.protocol }}"
+ ip: "{{ http_header_vars.ip }}"
+ port: "{{ http_header_vars.port }}"
+ register: get_http_header
+ changed_when: false
+
+- name: remove assert changed and gone
+ assert:
+ that:
+ - http_no_header is changed
+ - http_no_header.operation_type == 'removed'
+ - http_no_header.binding_info is defined
+ - http_no_header.binding_info.ip == "{{ http_vars.ip }}"
+ - http_no_header.binding_info.port == {{ http_vars.port }}
+ - http_no_header.binding_info.protocol == "{{ http_vars.protocol }}"
+ - get_http_no_header.binding is not defined
+ - http_header is changed
+ - http_header.binding_info is defined
+ - http_header.operation_type == 'removed'
+ - http_header.binding_info.ip == "{{ http_header_vars.ip }}"
+ - http_header.binding_info.port == {{ http_header_vars.port }}
+ - http_header.binding_info.protocol == "{{ http_header_vars.protocol }}"
+ - http_header.binding_info.hostheader == "{{ http_header_vars.header }}"
+ - get_http_header.binding is not defined
+
+#remove idem
+#change false, bindings gone
+- name: idem remove http binding no header
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: absent
+ protocol: "{{ http_vars.protocol }}"
+ ip: "{{ http_vars.ip }}"
+ port: "{{ http_vars.port }}"
+ register: http_no_header
+
+- name: get binding info no header
+ test_get_webbindings:
+ name: "{{ test_iis_site_name }}"
+ protocol: "{{ http_vars.protocol }}"
+ ip: "{{ http_vars.ip }}"
+ port: "{{ http_vars.port }}"
+ register: get_http_no_header
+ changed_when: false
+
+- name: idem remove http binding with header
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: absent
+ host_header: "{{ http_header_vars.header }}"
+ protocol: "{{ http_header_vars.protocol }}"
+ ip: "{{ http_header_vars.ip }}"
+ port: "{{ http_header_vars.port }}"
+ register: http_header
+
+- name: get binding info header
+ test_get_webbindings:
+ name: "{{ test_iis_site_name }}"
+ host_header: "{{ http_header_vars.header }}"
+ protocol: "{{ http_header_vars.protocol }}"
+ ip: "{{ http_header_vars.ip }}"
+ port: "{{ http_header_vars.port }}"
+ register: get_http_header
+ changed_when: false
+
+- name: idem remove assert changed and gone
+ assert:
+ that:
+ - http_no_header is not changed
+ - http_no_header.binding_info is not defined
+ - get_http_no_header.binding is not defined
+ - http_header is not changed
+ - http_header.binding_info is not defined
+ - get_http_header.binding is not defined
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/tasks/https-ge6.2.yml b/ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/tasks/https-ge6.2.yml
new file mode 100644
index 000000000..f883c673f
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/tasks/https-ge6.2.yml
@@ -0,0 +1,459 @@
+##############
+### CM Add ###
+##############
+#changed true, check nothing present
+- name: CM add https binding no header
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: present
+ protocol: "{{ https_vars.protocol }}"
+ ip: "{{ https_vars.ip }}"
+ port: "{{ https_vars.port }}"
+ certificate_hash: "{{ thumbprint1.stdout_lines[0] }}"
+ register: https_no_header
+ check_mode: yes
+
+- name: CM get binding info no header
+ test_get_webbindings:
+ name: "{{ test_iis_site_name }}"
+ protocol: "{{ https_vars.protocol }}"
+ ip: "{{ https_vars.ip }}"
+ port: "{{ https_vars.port }}"
+ register: get_https_no_header
+ changed_when: false
+
+- name: CM add https binding with header and SNI
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: present
+ host_header: "{{ https_header_vars.header }}"
+ protocol: "{{ https_header_vars.protocol }}"
+ ip: "{{ https_header_vars.ip }}"
+ port: "{{ https_header_vars.port }}"
+ ssl_flags: 1
+ certificate_hash: "{{ thumbprint1.stdout_lines[0] }}"
+ register: https_header
+ check_mode: yes
+
+- name: CM get binding info header
+ test_get_webbindings:
+ name: "{{ test_iis_site_name }}"
+ host_header: "{{ https_header_vars.header }}"
+ protocol: "{{ https_header_vars.protocol }}"
+ ip: "{{ https_header_vars.ip }}"
+ port: "{{ https_header_vars.port }}"
+ register: get_https_header
+ changed_when: false
+
+- name: CM assert changed, but not added
+ assert:
+ that:
+ - https_no_header is changed
+ - https_no_header.operation_type == 'added'
+ - https_no_header.binding_info is none
+ - get_https_no_header.binding is not defined
+ - https_header is changed
+ - https_header.operation_type == 'added'
+ - https_header.binding_info is none
+ - get_https_header.binding is not defined
+
+###########
+### Add ###
+###########
+#changed true, new bindings present
+- name: add https binding no header
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: present
+ protocol: "{{ https_vars.protocol }}"
+ ip: "{{ https_vars.ip }}"
+ port: "{{ https_vars.port }}"
+ certificate_hash: "{{ thumbprint1.stdout_lines[0] }}"
+ register: https_no_header
+
+- name: get binding info no header
+ test_get_webbindings:
+ name: "{{ test_iis_site_name }}"
+ protocol: "{{ https_vars.protocol }}"
+ ip: "{{ https_vars.ip }}"
+ port: "{{ https_vars.port }}"
+ register: get_https_no_header
+ changed_when: false
+
+- name: add https binding with header SNI
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: present
+ host_header: "{{ https_header_vars.header }}"
+ protocol: "{{ https_header_vars.protocol }}"
+ ip: "{{ https_header_vars.ip }}"
+ port: "{{ https_header_vars.port }}"
+ ssl_flags: 1
+ certificate_hash: "{{ thumbprint1.stdout_lines[0] }}"
+ register: https_header
+
+- name: get binding info header
+ test_get_webbindings:
+ name: "{{ test_iis_site_name }}"
+ host_header: "{{ https_header_vars.header }}"
+ protocol: "{{ https_header_vars.protocol }}"
+ ip: "{{ https_header_vars.ip }}"
+ port: "{{ https_header_vars.port }}"
+ register: get_https_header
+ changed_when: false
+
+- name: assert changed and added
+ assert:
+ that:
+ - https_no_header is changed
+ - https_no_header.operation_type == 'added'
+ - https_no_header.binding_info is defined
+ - https_no_header.binding_info.protocol == "{{ https_vars.protocol }}"
+ - https_no_header.binding_info.ip == "{{ https_vars.ip }}"
+ - https_no_header.binding_info.port == {{ https_vars.port }}
+ - https_no_header.binding_info.hostheader == ''
+ - https_no_header.binding_info.certificateHash == "{{ thumbprint1.stdout_lines[0] }}"
+ - https_header is changed
+ - https_header.operation_type == 'added'
+ - https_header.binding_info is defined
+ - https_header.binding_info.hostheader == "{{ https_header_vars.header }}"
+ - https_header.binding_info.protocol == "{{ https_header_vars.protocol }}"
+ - https_header.binding_info.ip == "{{ https_header_vars.ip }}"
+ - https_header.binding_info.port == {{ https_header_vars.port }}
+ - https_header.binding_info.certificateHash == "{{ thumbprint1.stdout_lines[0] }}"
+ - https_header.binding_info.sslFlags == 1
+
+################
+### Idem Add ###
+################
+#changed false
+- name: idem add https binding no header
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: present
+ protocol: https
+ ip: '*'
+ port: 443
+ certificate_hash: "{{ thumbprint1.stdout_lines[0] }}"
+ register: https_no_header
+
+- name: idem add https binding with header and SNI
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: present
+ host_header: test.com
+ protocol: https
+ ip: '*'
+ port: 443
+ ssl_flags: 1
+ certificate_hash: "{{ thumbprint1.stdout_lines[0] }}"
+ register: https_header
+
+- name: idem assert not changed
+ assert:
+ that:
+ - https_no_header is not changed
+ - https_header is not changed
+
+#################
+### CM Modify ###
+#################
+# changed true, verify no changes occurred
+
+#modify sni
+- name: CM modify https binding with header, change cert
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: present
+ host_header: "{{ https_header_vars.header }}"
+ protocol: "{{ https_header_vars.protocol }}"
+ ip: "{{ https_header_vars.ip }}"
+ port: "{{ https_header_vars.port }}"
+ ssl_flags: 1
+ certificate_hash: "{{ thumbprint2.stdout_lines[0] }}"
+ register: https_header
+ check_mode: yes
+
+- name: get binding info header
+ test_get_webbindings:
+ name: "{{ test_iis_site_name }}"
+ host_header: "{{ https_header_vars.header }}"
+ protocol: "{{ https_header_vars.protocol }}"
+ ip: "{{ https_header_vars.ip }}"
+ port: "{{ https_header_vars.port }}"
+ register: get_https_header
+ changed_when: false
+
+- name: CM assert changed but old cert
+ assert:
+ that:
+ - https_header is changed
+ - https_header.operation_type == 'updated'
+ - https_header.binding_info is defined
+ - https_header.binding_info.ip == "{{ https_header_vars.ip }}"
+ - https_header.binding_info.port == {{ https_header_vars.port }}
+ - https_header.binding_info.protocol == "{{ https_header_vars.protocol }}"
+ - https_header.binding_info.hostheader == "{{ https_header_vars.header }}"
+ - https_header.binding_info.certificateHash == "{{ thumbprint1.stdout_lines[0] }}"
+ - https_header.binding_info.sslFlags == 1
+ - get_https_header.binding is defined
+ - get_https_header.binding.ip == "{{ https_header_vars.ip }}"
+ - get_https_header.binding.port == {{ https_header_vars.port }}
+ - get_https_header.binding.protocol == "{{ https_header_vars.protocol }}"
+ - get_https_header.binding.hostheader == "{{ https_header_vars.header }}"
+ - get_https_header.binding.certificateHash == "{{ thumbprint1.stdout_lines[0] }}"
+ - get_https_header.binding.sslFlags == 1
+
+##############
+### Modify ###
+##############
+# modify ssl flags
+- name: modify https binding with header, change cert
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: present
+ host_header: "{{ https_header_vars.header }}"
+ protocol: "{{ https_header_vars.protocol }}"
+ ip: "{{ https_header_vars.ip }}"
+ port: "{{ https_header_vars.port }}"
+ ssl_flags: 1
+ certificate_hash: "{{ thumbprint2.stdout_lines[0] }}"
+ register: https_header
+
+- name: get binding info header
+ test_get_webbindings:
+ name: "{{ test_iis_site_name }}"
+ host_header: "{{ https_header_vars.header }}"
+ protocol: "{{ https_header_vars.protocol }}"
+ ip: "{{ https_header_vars.ip }}"
+ port: "{{ https_header_vars.port }}"
+ register: get_https_header
+ changed_when: false
+
+- name: modify assert changed and new cert
+ assert:
+ that:
+ - https_header is changed
+ - https_header.operation_type == 'updated'
+ - https_header.binding_info is defined
+ - https_header.binding_info.ip == "{{ https_header_vars.ip }}"
+ - https_header.binding_info.port == {{ https_header_vars.port }}
+ - https_header.binding_info.protocol == "{{ https_header_vars.protocol }}"
+ - https_header.binding_info.hostheader == "{{ https_header_vars.header }}"
+ - https_header.binding_info.certificateHash == "{{ thumbprint2.stdout_lines[0] }}"
+ - https_header.binding_info.sslFlags == 1
+ - get_https_header.binding is defined
+ - get_https_header.binding.ip == "{{ https_header_vars.ip }}"
+ - get_https_header.binding.port == {{ https_header_vars.port }}
+ - get_https_header.binding.protocol == "{{ https_header_vars.protocol }}"
+ - get_https_header.binding.hostheader == "{{ https_header_vars.header }}"
+ - get_https_header.binding.certificateHash == "{{ thumbprint2.stdout_lines[0] }}"
+ - get_https_header.binding.sslFlags == 1
+
+###################
+### Idem Modify ###
+###################
+#changed false
+
+#idem modify ssl flags
+- name: idem modify https binding with header, enable SNI and change cert
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: present
+ host_header: "{{ https_header_vars.header }}"
+ protocol: "{{ https_header_vars.protocol }}"
+ ip: "{{ https_header_vars.ip }}"
+ port: "{{ https_header_vars.port }}"
+ ssl_flags: 1
+ certificate_hash: "{{ thumbprint2.stdout_lines[0] }}"
+ register: https_header
+
+- name: idem assert not changed
+ assert:
+ that:
+ - https_header is not changed
+
+#################
+### CM Remove ###
+#################
+#changed true, bindings still present
+- name: cm remove https binding no header
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: absent
+ protocol: "{{ https_vars.protocol }}"
+ ip: "{{ https_vars.ip }}"
+ port: "{{ https_vars.port }}"
+ register: https_no_header
+ check_mode: yes
+
+- name: get binding info no header
+ test_get_webbindings:
+ name: "{{ test_iis_site_name }}"
+ protocol: "{{ https_vars.protocol }}"
+ ip: "{{ https_vars.ip }}"
+ port: "{{ https_vars.port }}"
+ register: get_https_no_header
+ changed_when: false
+
+- name: cm remove https binding with header
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: absent
+ host_header: "{{ https_header_vars.header }}"
+ protocol: "{{ https_header_vars.protocol }}"
+ ip: "{{ https_header_vars.ip }}"
+ port: "{{ https_header_vars.port }}"
+ register: https_header
+ check_mode: yes
+
+- name: get binding info header
+ test_get_webbindings:
+ name: "{{ test_iis_site_name }}"
+ host_header: "{{ https_header_vars.header }}"
+ protocol: "{{ https_header_vars.protocol }}"
+ ip: "{{ https_header_vars.ip }}"
+ port: "{{ https_header_vars.port }}"
+ register: get_https_header
+ changed_when: false
+
+- name: cm remove assert changed, but still present
+ assert:
+ that:
+ - https_no_header is changed
+ - https_no_header.operation_type == 'removed'
+ - https_no_header.binding_info is defined
+ - https_no_header.binding_info.ip == "{{ https_vars.ip }}"
+ - https_no_header.binding_info.port == {{ https_vars.port }}
+ - https_no_header.binding_info.protocol == "{{ https_vars.protocol }}"
+ - get_https_no_header.binding is defined
+ - get_https_no_header.binding.ip == "{{ https_vars.ip }}"
+ - get_https_no_header.binding.port == {{ https_vars.port }}
+ - get_https_no_header.binding.protocol == "{{ https_vars.protocol }}"
+ - get_https_no_header.binding.certificateHash == "{{ thumbprint1.stdout_lines[0] }}"
+ - https_header is changed
+ - https_header.binding_info is defined
+ - https_header.operation_type == 'removed'
+ - https_header.binding_info.ip == "{{ https_header_vars.ip }}"
+ - https_header.binding_info.port == {{ https_header_vars.port }}
+ - https_header.binding_info.protocol == "{{ https_header_vars.protocol }}"
+ - https_header.binding_info.hostheader == "{{ https_header_vars.header }}"
+ - get_https_header.binding is defined
+ - get_https_header.binding.ip == "{{ https_header_vars.ip }}"
+ - get_https_header.binding.port == {{ https_header_vars.port }}
+ - get_https_header.binding.protocol == "{{ https_header_vars.protocol }}"
+ - get_https_header.binding.hostheader == "{{ https_header_vars.header }}"
+ - get_https_header.binding.certificateHash == "{{ thumbprint2.stdout_lines[0] }}"
+
+##############
+### remove ###
+##############
+#changed true, bindings gone
+- name: remove https binding no header
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: absent
+ protocol: "{{ https_vars.protocol }}"
+ ip: "{{ https_vars.ip }}"
+ port: "{{ https_vars.port }}"
+ register: https_no_header
+
+- name: get binding info no header
+ test_get_webbindings:
+ name: "{{ test_iis_site_name }}"
+ protocol: "{{ https_vars.protocol }}"
+ ip: "{{ https_vars.ip }}"
+ port: "{{ https_vars.port }}"
+ register: get_https_no_header
+ changed_when: false
+
+- name: remove https binding with header
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: absent
+ host_header: "{{ https_header_vars.header }}"
+ protocol: "{{ https_header_vars.protocol }}"
+ ip: "{{ https_header_vars.ip }}"
+ port: "{{ https_header_vars.port }}"
+ register: https_header
+
+- name: get binding info header
+ test_get_webbindings:
+ name: "{{ test_iis_site_name }}"
+ host_header: "{{ https_header_vars.header }}"
+ protocol: "{{ https_header_vars.protocol }}"
+ ip: "{{ https_header_vars.ip }}"
+ port: "{{ https_header_vars.port }}"
+ register: get_https_header
+ changed_when: false
+
+- name: remove assert changed and gone
+ assert:
+ that:
+ - https_no_header is changed
+ - https_no_header.binding_info is defined
+ - https_no_header.operation_type == 'removed'
+ - https_no_header.binding_info.ip == "{{ https_vars.ip }}"
+ - https_no_header.binding_info.port == {{ https_vars.port }}
+ - https_no_header.binding_info.protocol == "{{ https_vars.protocol }}"
+ - get_https_no_header.binding is not defined
+ - https_header is changed
+ - https_header.binding_info is defined
+ - https_header.operation_type == 'removed'
+ - https_header.binding_info.ip == "{{ https_header_vars.ip }}"
+ - https_header.binding_info.port == {{ https_header_vars.port }}
+ - https_header.binding_info.protocol == "{{ https_header_vars.protocol }}"
+ - https_header.binding_info.hostheader == "{{ https_header_vars.header }}"
+ - get_https_header.binding is not defined
+
+###################
+### remove idem ###
+###################
+#change false, bindings gone
+- name: idem remove https binding no header
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: absent
+ protocol: "{{ https_vars.protocol }}"
+ ip: "{{ https_vars.ip }}"
+ port: "{{ https_vars.port }}"
+ register: https_no_header
+
+- name: get binding info no header
+ test_get_webbindings:
+ name: "{{ test_iis_site_name }}"
+ protocol: "{{ https_vars.protocol }}"
+ ip: "{{ https_vars.ip }}"
+ port: "{{ https_vars.port }}"
+ register: get_https_no_header
+ changed_when: false
+
+- name: idem remove https binding with header
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: absent
+ host_header: "{{ https_header_vars.header }}"
+ protocol: "{{ https_header_vars.protocol }}"
+ ip: "{{ https_header_vars.ip }}"
+ port: "{{ https_header_vars.port }}"
+ register: https_header
+
+- name: get binding info header
+ test_get_webbindings:
+ name: "{{ test_iis_site_name }}"
+ host_header: "{{ https_header_vars.header }}"
+ protocol: "{{ https_header_vars.protocol }}"
+ ip: "{{ https_header_vars.ip }}"
+ port: "{{ https_header_vars.port }}"
+ register: get_https_header
+ changed_when: false
+
+- name: idem remove assert changed and gone
+ assert:
+ that:
+ - https_no_header is not changed
+ - https_no_header.binding_info is not defined
+ - get_https_no_header.binding is not defined
+ - https_header is not changed
+ - https_header.binding_info is not defined
+ - get_https_header.binding is not defined
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/tasks/https-lt6.2.yml b/ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/tasks/https-lt6.2.yml
new file mode 100644
index 000000000..1950641e8
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/tasks/https-lt6.2.yml
@@ -0,0 +1,423 @@
+##############
+### CM Add ###
+##############
+#changed true, check nothing present
+- name: CM add https binding no header
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: present
+ protocol: "{{ https_vars.protocol }}"
+ ip: "{{ https_vars.ip }}"
+ port: "{{ https_vars.port }}"
+ certificate_hash: "{{ thumbprint1.stdout_lines[0] }}"
+ register: https_no_header
+ check_mode: yes
+
+- name: CM get binding info no header
+ test_get_webbindings:
+ name: "{{ test_iis_site_name }}"
+ protocol: "{{ https_vars.protocol }}"
+ ip: "{{ https_vars.ip }}"
+ port: "{{ https_vars.port }}"
+ register: get_https_no_header
+ changed_when: false
+
+- name: CM assert changed, but not added
+ assert:
+ that:
+ - https_no_header is changed
+ - https_no_header.operation_type == 'added'
+ - https_no_header.binding_info is none
+ - get_https_no_header.binding is not defined
+
+###########
+### Add ###
+###########
+#changed true, new bindings present
+- name: add https binding no header
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: present
+ protocol: "{{ https_vars.protocol }}"
+ ip: "{{ https_vars.ip }}"
+ port: "{{ https_vars.port }}"
+ certificate_hash: "{{ thumbprint1.stdout_lines[0] }}"
+ register: https_no_header
+
+- name: assert changed and added
+ assert:
+ that:
+ - https_no_header is changed
+ - https_no_header.binding_info is defined
+ - https_no_header.operation_type == 'added'
+ - https_no_header.binding_info.ip == "{{ https_vars.ip }}"
+ - https_no_header.binding_info.port == {{ https_vars.port }}
+ - https_no_header.binding_info.protocol == "{{ https_vars.protocol }}"
+ - https_no_header.binding_info.hostheader == ''
+ - https_no_header.binding_info.certificateHash == "{{ thumbprint1.stdout_lines[0] }}"
+
+################
+### Idem Add ###
+################
+#changed false
+- name: idem add https binding no header
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: present
+ protocol: "{{ https_vars.protocol }}"
+ ip: "{{ https_vars.ip }}"
+ port: "{{ https_vars.port }}"
+ certificate_hash: "{{ thumbprint1.stdout_lines[0] }}"
+ register: https_no_header
+
+- name: idem assert not changed
+ assert:
+ that:
+ - https_no_header is not changed
+
+#################
+### CM Modify ###
+#################
+# changed true, verify no changes occurred
+
+#modify sni
+- name: CM modify https binding change cert
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: present
+ protocol: "{{ https_vars.protocol }}"
+ ip: "{{ https_vars.ip }}"
+ port: "{{ https_vars.port }}"
+ certificate_hash: "{{ thumbprint2.stdout_lines[0] }}"
+ register: https_no_header
+ check_mode: yes
+
+- name: get binding info header
+ test_get_webbindings:
+ name: "{{ test_iis_site_name }}"
+ protocol: "{{ https_vars.protocol }}"
+ ip: "{{ https_vars.ip }}"
+ port: "{{ https_vars.port }}"
+ register: get_https_no_header
+ changed_when: false
+
+- name: CM assert changed but old cert
+ assert:
+ that:
+ - https_no_header is changed
+ - https_no_header.operation_type == 'updated'
+ - https_no_header.binding_info is defined
+ - https_no_header.binding_info.ip == "{{ https_vars.ip }}"
+ - https_no_header.binding_info.port == {{ https_vars.port }}
+ - https_no_header.binding_info.protocol == "{{ https_vars.protocol }}"
+ - https_no_header.binding_info.certificateHash == "{{ thumbprint1.stdout_lines[0] }}"
+ - get_https_no_header.binding is defined
+ - get_https_no_header.binding.ip == "{{ https_vars.ip }}"
+ - get_https_no_header.binding.port == {{ https_vars.port }}
+ - get_https_no_header.binding.protocol == "{{ https_vars.protocol }}"
+ - get_https_no_header.binding.certificateHash == "{{ thumbprint1.stdout_lines[0] }}"
+
+##############
+### Modify ###
+##############
+# modify ssl flags
+- name: modify https binding, change cert
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: present
+ protocol: "{{ https_vars.protocol }}"
+ ip: "{{ https_vars.ip }}"
+ port: "{{ https_vars.port }}"
+ certificate_hash: "{{ thumbprint2.stdout_lines[0] }}"
+ register: https_no_header
+
+- name: get binding info header
+ test_get_webbindings:
+ name: "{{ test_iis_site_name }}"
+ protocol: "{{ https_vars.protocol }}"
+ ip: "{{ https_vars.ip }}"
+ port: "{{ https_vars.port }}"
+ register: get_https_no_header
+ changed_when: false
+
+- name: modify assert changed and new cert
+ assert:
+ that:
+ - https_no_header is changed
+ - https_no_header.operation_type == 'updated'
+ - https_no_header.binding_info is defined
+ - https_no_header.binding_info.ip == "{{ https_vars.ip }}"
+ - https_no_header.binding_info.port == {{ https_vars.port }}
+ - https_no_header.binding_info.protocol == "{{ https_vars.protocol }}"
+ - https_no_header.binding_info.certificateHash == "{{ thumbprint2.stdout_lines[0] }}"
+ - get_https_no_header.binding is defined
+ - get_https_no_header.binding.ip == "{{ https_vars.ip }}"
+ - get_https_no_header.binding.port == {{ https_vars.port }}
+ - get_https_no_header.binding.protocol == "{{ https_vars.protocol }}"
+ - get_https_no_header.binding.hostheader == ''
+ - get_https_no_header.binding.certificateHash == "{{ thumbprint2.stdout_lines[0] }}"
+
+###################
+### Idem Modify ###
+###################
+#changed false
+
+#idem modify ssl flags
+- name: idem modify https binding and change cert
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: present
+ protocol: "{{ https_vars.protocol }}"
+ ip: "{{ https_vars.ip }}"
+ port: "{{ https_vars.port }}"
+ certificate_hash: "{{ thumbprint2.stdout_lines[0] }}"
+ register: https_header
+
+- name: idem assert not changed
+ assert:
+ that:
+ - https_header is not changed
+
+#################
+### CM Remove ###
+#################
+#changed true, bindings still present
+- name: cm remove https binding no header
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: absent
+ protocol: "{{ https_vars.protocol }}"
+ ip: "{{ https_vars.ip }}"
+ port: "{{ https_vars.port }}"
+ register: https_no_header
+ check_mode: yes
+
+- name: get binding info no header
+ test_get_webbindings:
+ name: "{{ test_iis_site_name }}"
+ protocol: "{{ https_vars.protocol }}"
+ ip: "{{ https_vars.ip }}"
+ port: "{{ https_vars.port }}"
+ register: get_https_no_header
+ changed_when: false
+
+- name: cm remove assert changed, but still present
+ assert:
+ that:
+ - https_no_header is changed
+ - https_no_header.operation_type == 'removed'
+ - https_no_header.binding_info is defined
+ - https_no_header.binding_info.ip == "{{ https_vars.ip }}"
+ - https_no_header.binding_info.port == {{ https_vars.port }}
+ - https_no_header.binding_info.protocol == "{{ https_vars.protocol }}"
+ - https_no_header.binding_info.certificateHash == "{{ thumbprint2.stdout_lines[0] }}"
+ - get_https_no_header.binding is defined
+ - get_https_no_header.binding.ip == "{{ https_vars.ip }}"
+ - get_https_no_header.binding.port == {{ https_vars.port }}
+ - get_https_no_header.binding.protocol == "{{ https_vars.protocol }}"
+ - get_https_no_header.binding.certificateHash == "{{ thumbprint2.stdout_lines[0] }}"
+
+##############
+### remove ###
+##############
+#changed true, bindings gone
+- name: remove https binding no header
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: absent
+ protocol: "{{ https_vars.protocol }}"
+ ip: "{{ https_vars.ip }}"
+ port: "{{ https_vars.port }}"
+ register: https_no_header
+
+- name: get binding info no header
+ test_get_webbindings:
+ name: "{{ test_iis_site_name }}"
+ protocol: "{{ https_vars.protocol }}"
+ ip: "{{ https_vars.ip }}"
+ port: "{{ https_vars.port }}"
+ register: get_https_no_header
+ changed_when: false
+
+- name: remove assert changed and gone
+ assert:
+ that:
+ - https_no_header is changed
+ - https_no_header.operation_type == 'removed'
+ - https_no_header.binding_info is defined
+ - https_no_header.binding_info.ip == "{{ https_vars.ip }}"
+ - https_no_header.binding_info.port == {{ https_vars.port }}
+ - https_no_header.binding_info.protocol == "{{ https_vars.protocol }}"
+ - get_https_no_header.binding is not defined
+
+###################
+### remove idem ###
+###################
+#change false, bindings gone
+- name: idem remove https binding no header
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: absent
+ protocol: "{{ https_vars.protocol }}"
+ ip: "{{ https_vars.ip }}"
+ port: "{{ https_vars.port }}"
+ register: https_no_header
+
+- name: get binding info no header
+ test_get_webbindings:
+ name: "{{ test_iis_site_name }}"
+ protocol: "{{ https_vars.protocol }}"
+ ip: "{{ https_vars.ip }}"
+ port: "{{ https_vars.port }}"
+ register: get_https_no_header
+ changed_when: false
+
+- name: idem remove assert changed and gone
+ assert:
+ that:
+ - https_no_header is not changed
+ - https_no_header.binding_info is not defined
+ - get_https_no_header.binding is not defined
+
+
+##################
+### WC Testing ###
+##################
+
+# Unfortunately this does not work due to some strange errors
+# that are caused when using a self signed wildcard cert.
+# I'm leaving this here in case someone finds a solution in the
+# future.
+
+# - name: add https binding wildcard with header
+# win_iis_webbinding:
+# name: "{{ test_iis_site_name }}"
+# state: present
+# host_header: "{{ https_wc_vars.header }}"
+# protocol: "{{ https_wc_vars.protocol }}"
+# ip: "{{ https_wc_vars.ip }}"
+# port: "{{ https_wc_vars.port }}"
+# certificate_hash: "{{ thumbprint_wc.stdout_lines[0] }}"
+# register: https_header
+
+# - name: assert changed and added
+# assert:
+# that:
+# - https_header is changed
+# - https_header.added is defined
+# - https_header.added.ip == "{{ https_wc_vars.ip }}"
+# - https_header.added.port == {{ https_wc_vars.port }}
+# - https_header.added.protocol == "{{ https_wc_vars.protocol }}"
+# - https_header.added.hostheader == "{{ https_wc_vars.header }}"
+# - https_header.added.certificateHash == "{{ thumbprint_wc.stdout_lines[0] }}"
+
+
+# - name: idem add https binding wildcard with header
+# win_iis_webbinding:
+# name: "{{ test_iis_site_name }}"
+# state: present
+# host_header: "{{ https_wc_vars.header }}"
+# protocol: "{{ https_wc_vars.protocol }}"
+# ip: "{{ https_wc_vars.ip }}"
+# port: "{{ https_wc_vars.port }}"
+# certificate_hash: "{{ thumbprint_wc.stdout_lines[0] }}"
+# register: https_header
+
+
+# - name: cm remove wildcard https binding
+# win_iis_webbinding:
+# name: "{{ test_iis_site_name }}"
+# state: absent
+# host_header: "{{ https_wc_vars.header }}"
+# protocol: "{{ https_wc_vars.protocol }}"
+# ip: "{{ https_wc_vars.ip }}"
+# port: "{{ https_wc_vars.port }}"
+# register: https_header
+# check_mode: yes
+
+# - name: get binding info header
+# test_get_webbindings:
+# name: "{{ test_iis_site_name }}"
+# host_header: "{{ https_wc_vars.header }}"
+# protocol: "{{ https_wc_vars.protocol }}"
+# ip: "{{ https_wc_vars.ip }}"
+# port: "{{ https_wc_vars.port }}"
+# register: get_https_header
+# changed_when: false
+
+# - name: cm remove assert changed, but still present
+# assert:
+# that:
+# - https_header is changed
+# - https_header.removed is defined
+# - https_header.removed.ip == "{{ https_wc_vars.ip }}"
+# - https_header.removed.port == {{ https_wc_vars.port }}
+# - https_header.removed.protocol == "{{ https_wc_vars.protocol }}"
+# - https_header.removed.hostheader == "{{ https_wc_vars.header }}"
+# - https_header.removed.certificateHash == "{{ thumbprint_wc.stdout_lines[0] }}"
+# - get_https_header.binding is defined
+# - get_https_header.removed.ip == "{{ https_wc_vars.ip }}"
+# - get_https_header.removed.port == {{ https_wc_vars.port }}
+# - get_https_header.removed.protocol == "{{ https_wc_vars.protocol }}"
+# - get_https_header.removed.hostheader == "{{ https_wc_vars.header }}"
+# - get_https_header.removed.certificateHash == "{{ thumbprint_wc.stdout_lines[0] }}"
+
+# - name: remove wildcard https binding
+# win_iis_webbinding:
+# name: "{{ test_iis_site_name }}"
+# state: absent
+# host_header: "{{ https_wc_vars.header }}"
+# protocol: "{{ https_wc_vars.protocol }}"
+# ip: "{{ https_wc_vars.ip }}"
+# port: "{{ https_wc_vars.port }}"
+# register: https_header
+
+# - name: get binding info header
+# test_get_webbindings:
+# name: "{{ test_iis_site_name }}"
+# host_header: "{{ https_wc_vars.header }}"
+# protocol: "{{ https_wc_vars.protocol }}"
+# ip: "{{ https_wc_vars.ip }}"
+# port: "{{ https_wc_vars.port }}"
+# register: get_https_header
+# changed_when: false
+
+
+# - name: remove assert changed and gone
+# assert:
+# that:
+# - https_header is changed
+# - https_header.removed is defined
+# - https_header.removed.ip == "{{ https_wc_vars.ip }}"
+# - https_header.removed.port == {{ https_wc_vars.port }}
+# - https_header.removed.protocol == "{{ https_wc_vars.protocol }}"
+# - https_header.removed.hostheader == "{{ https_wc_vars.header }}"
+# - https_header.removed.certificateHash == "{{ thumbprint_wc.stdout_lines[0] }}"
+# - get_https_header.binding is not defined
+
+# - name: idem remove wildcard https binding
+# win_iis_webbinding:
+# name: "{{ test_iis_site_name }}"
+# state: absent
+# host_header: "{{ https_wc_vars.header }}"
+# protocol: "{{ https_wc_vars.protocol }}"
+# ip: "{{ https_wc_vars.ip }}"
+# port: "{{ https_wc_vars.port }}"
+# register: https_header
+
+# - name: get binding info header
+# test_get_webbindings:
+# name: "{{ test_iis_site_name }}"
+# host_header: "{{ https_wc_vars.header }}"
+# protocol: "{{ https_wc_vars.protocol }}"
+# ip: "{{ https_wc_vars.ip }}"
+# port: "{{ https_wc_vars.port }}"
+# register: get_https_header
+# changed_when: false
+
+# - name: idem remove assert changed and gone
+# assert:
+# that:
+# - https_header is not changed
+# - https_header.removed is not defined
+# - get_https_header.binding is not defined
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/tasks/main.yml
new file mode 100644
index 000000000..ee12ff78b
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/tasks/main.yml
@@ -0,0 +1,62 @@
+---
+# Cannot use win_feature to install IIS on Server 2008.
+# Run a brief check and skip hosts that don't support
+# that operation
+#seems "raw" is the only module that works on 2008 non-r2. win_command and win_shell both failed
+- name: register os version (seems integration tests don't gather this fact)
+ raw: powershell.exe "gwmi Win32_OperatingSystem | select -expand version"
+ register: os_version
+ changed_when: False
+
+- block:
+ - include_tasks: setup.yml
+ - include_tasks: http.yml
+ - include_tasks: https-lt6.2.yml
+ when: os_version.stdout_lines[0] is version('6.2','lt')
+ - include_tasks: https-ge6.2.yml
+ when: os_version.stdout_lines[0] is version('6.2','ge')
+ - include_tasks: failures.yml
+
+ always:
+ - name: get all websites from server
+ raw: powershell.exe "(get-website).name"
+ register: existing_sites
+
+ - name: ensure all sites are removed for clean testing
+ win_iis_website:
+ name: "{{ item }}"
+ state: absent
+ with_items:
+ - "{{ existing_sites.stdout_lines }}"
+
+ - name: cleanup certreq files
+ ansible.windows.win_file:
+ path: "{{ item }}"
+ state: absent
+ with_items:
+ - c:\windows\temp\certreq1.txt
+ - c:\windows\temp\certreq2.txt
+ - c:\windows\temp\certreqwc.txt
+ - c:\windows\temp\certreqresp1.txt
+ - c:\windows\temp\certreqresp2.txt
+ - c:\windows\temp\certreqrespwc.txt
+
+ - name: remove certs
+ raw: 'remove-item cert:\localmachine\my\{{ item }} -force -ea silentlycontinue'
+ with_items:
+ - "{{ thumbprint1.stdout_lines[0] }}"
+ - "{{ thumbprint2.stdout_lines[0] }}"
+ - "{{ thumbprint_wc.stdout_lines[0] }}"
+
+ - name: remove IIS features after test
+ ansible.windows.win_feature:
+ name: Web-Server
+ state: absent
+ includ_sub_features: True
+ include_management_tools: True
+ register: feature_uninstall
+
+ - name: reboot after feature install
+ ansible.windows.win_reboot:
+ when: feature_uninstall.reboot_required
+ when: os_version.stdout_lines[0] is version('6.1','gt')
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/tasks/setup.yml b/ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/tasks/setup.yml
new file mode 100644
index 000000000..234cc400d
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_iis_webbinding/tasks/setup.yml
@@ -0,0 +1,93 @@
+- name: reboot before feature install to ensure server is in clean state
+ ansible.windows.win_reboot:
+
+- name: ensure IIS features are installed
+ ansible.windows.win_feature:
+ name: Web-Server
+ state: present
+ includ_sub_features: True
+ include_management_tools: True
+ register: feature_install
+
+- name: reboot after feature install
+ ansible.windows.win_reboot:
+ when: feature_install.reboot_required
+
+- name: get all websites from server
+ raw: powershell.exe "(get-website).name"
+ register: existing_sites
+
+- name: ensure all sites are removed for clean testing
+ win_iis_website:
+ name: "{{ item }}"
+ state: absent
+ with_items:
+ - "{{ existing_sites.stdout_lines }}"
+
+- name: add testing site {{ test_iis_site_name }}
+ win_iis_website:
+ name: "{{ test_iis_site_name }}"
+ physical_path: c:\inetpub\wwwroot
+
+- name: ensure all bindings are removed prior to starting testing
+ win_iis_webbinding:
+ name: "{{ test_iis_site_name }}"
+ state: absent
+ protocol: "{{ item.protocol }}"
+ port: "{{ item.port }}"
+ with_items:
+ - {protocol: http, port: 80}
+ - {protocol: https, port: 443}
+
+- name: copy certreq file
+ ansible.windows.win_copy:
+ content: |-
+ [NewRequest]
+ Subject = "CN={{ item.name }}"
+ KeyLength = 2048
+ KeyAlgorithm = RSA
+ MachineKeySet = true
+ RequestType = Cert
+ dest: "{{ item.dest }}"
+ with_items:
+ - {name: test.com, dest: 'c:\windows\temp\certreq1.txt'}
+ - {name: test1.com, dest: 'c:\windows\temp\certreq2.txt'}
+ - {name: '*.test.com', dest: 'c:\windows\temp\certreqwc.txt'}
+
+- name: make sure response files are absent
+ ansible.windows.win_file:
+ path: "{{ item }}"
+ state: absent
+ with_items:
+ - 'c:\windows\temp\certreqresp1.txt'
+ - 'c:\windows\temp\certreqresp2.txt'
+ - 'c:\windows\temp\certreqrespwc.txt'
+
+- name: create self signed cert from certreq
+ ansible.windows.win_command: certreq -new -machine {{ item.req }} {{ item.resp }}
+ with_items:
+ - {req: 'c:\windows\temp\certreq1.txt', resp: 'c:\windows\temp\certreqresp1.txt'}
+ - {req: 'c:\windows\temp\certreq2.txt', resp: 'c:\windows\temp\certreqresp2.txt'}
+ - {req: 'c:\windows\temp\certreqwc.txt', resp: 'c:\windows\temp\certreqrespwc.txt'}
+
+- name: register certificate thumbprint1
+ raw: '(gci Cert:\LocalMachine\my | ? {$_.subject -eq "CN=test.com"})[0].Thumbprint'
+ register: thumbprint1
+
+- name: register certificate thumbprint2
+ raw: '(gci Cert:\LocalMachine\my | ? {$_.subject -eq "CN=test1.com"})[0].Thumbprint'
+ register: thumbprint2
+
+- name: register certificate thumbprint_wc
+ raw: '(gci Cert:\LocalMachine\my | ? {$_.subject -eq "CN=*.test.com"})[0].Thumbprint'
+ register: thumbprint_wc
+
+- debug:
+ var: thumbprint1.stdout
+ verbosity: 1
+- debug:
+ var: thumbprint2.stdout
+ verbosity: 1
+- debug:
+ var: thumbprint_wc.stdout
+ verbosity: 1
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_inet_proxy/aliases b/ansible_collections/community/windows/tests/integration/targets/win_inet_proxy/aliases
new file mode 100644
index 000000000..423ce3910
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_inet_proxy/aliases
@@ -0,0 +1 @@
+shippable/windows/group2
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_inet_proxy/library/win_inet_proxy_info.ps1 b/ansible_collections/community/windows/tests/integration/targets/win_inet_proxy/library/win_inet_proxy_info.ps1
new file mode 100644
index 000000000..76bf03ec9
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_inet_proxy/library/win_inet_proxy_info.ps1
@@ -0,0 +1,275 @@
+#!powershell
+
+# Copyright: (c) 2019, Ansible Project
+# 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.AddType
+
+$spec = @{
+ options = @{
+ connection = @{ type = "str" }
+ }
+ supports_check_mode = $true
+}
+
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
+
+$connection = $module.Params.connection
+
+$win_inet_invoke = @'
+using Microsoft.Win32.SafeHandles;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Runtime.ConstrainedExecution;
+using System.Runtime.InteropServices;
+
+namespace Ansible.WinINetProxyInfo
+{
+ internal class NativeHelpers
+ {
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ public class INTERNET_PER_CONN_OPTION_LISTW : IDisposable
+ {
+ public UInt32 dwSize;
+ public IntPtr pszConnection;
+ public UInt32 dwOptionCount;
+ public UInt32 dwOptionError;
+ public IntPtr pOptions;
+
+ public INTERNET_PER_CONN_OPTION_LISTW()
+ {
+ dwSize = (UInt32)Marshal.SizeOf(this);
+ }
+
+ public void Dispose()
+ {
+ if (pszConnection != IntPtr.Zero)
+ Marshal.FreeHGlobal(pszConnection);
+ if (pOptions != IntPtr.Zero)
+ Marshal.FreeHGlobal(pOptions);
+ GC.SuppressFinalize(this);
+ }
+ ~INTERNET_PER_CONN_OPTION_LISTW() { this.Dispose(); }
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ public class INTERNET_PER_CONN_OPTIONW : IDisposable
+ {
+ public INTERNET_PER_CONN_OPTION dwOption;
+ public ValueUnion Value;
+
+ [StructLayout(LayoutKind.Explicit)]
+ public class ValueUnion
+ {
+ [FieldOffset(0)]
+ public UInt32 dwValue;
+
+ [FieldOffset(0)]
+ public IntPtr pszValue;
+
+ [FieldOffset(0)]
+ public System.Runtime.InteropServices.ComTypes.FILETIME ftValue;
+ }
+
+ public void Dispose()
+ {
+ // We can't just check if Value.pszValue is not IntPtr.Zero as the union means it could be set even
+ // when the value is a UInt32 or FILETIME. We check against a known string option type and only free
+ // the value in those cases.
+ List<INTERNET_PER_CONN_OPTION> stringOptions = new List<INTERNET_PER_CONN_OPTION>
+ {
+ { INTERNET_PER_CONN_OPTION.INTERNET_PER_CONN_AUTOCONFIG_URL },
+ { INTERNET_PER_CONN_OPTION.INTERNET_PER_CONN_PROXY_BYPASS },
+ { INTERNET_PER_CONN_OPTION.INTERNET_PER_CONN_PROXY_SERVER }
+ };
+ if (Value != null && Value.pszValue != IntPtr.Zero && stringOptions.Contains(dwOption))
+ Marshal.FreeHGlobal(Value.pszValue);
+ GC.SuppressFinalize(this);
+ }
+ ~INTERNET_PER_CONN_OPTIONW() { this.Dispose(); }
+ }
+
+ public enum INTERNET_OPTION : uint
+ {
+ INTERNET_OPTION_PER_CONNECTION_OPTION = 75,
+ }
+
+ public enum INTERNET_PER_CONN_OPTION : uint
+ {
+ INTERNET_PER_CONN_FLAGS = 1,
+ INTERNET_PER_CONN_PROXY_SERVER = 2,
+ INTERNET_PER_CONN_PROXY_BYPASS = 3,
+ INTERNET_PER_CONN_AUTOCONFIG_URL = 4,
+ INTERNET_PER_CONN_AUTODISCOVERY_FLAGS = 5,
+ INTERNET_PER_CONN_FLAGS_UI = 10, // IE8+ - Included with Windows 7 and Server 2008 R2
+ }
+
+ [Flags]
+ public enum PER_CONN_FLAGS : uint
+ {
+ PROXY_TYPE_DIRECT = 0x00000001,
+ PROXY_TYPE_PROXY = 0x00000002,
+ PROXY_TYPE_AUTO_PROXY_URL = 0x00000004,
+ PROXY_TYPE_AUTO_DETECT = 0x00000008,
+ }
+ }
+
+ internal class NativeMethods
+ {
+ [DllImport("Wininet.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern bool InternetQueryOptionW(
+ IntPtr hInternet,
+ NativeHelpers.INTERNET_OPTION dwOption,
+ SafeMemoryBuffer lpBuffer,
+ ref UInt32 lpdwBufferLength);
+ }
+
+ internal class SafeMemoryBuffer : SafeHandleZeroOrMinusOneIsInvalid
+ {
+ public SafeMemoryBuffer() : base(true) { }
+ public SafeMemoryBuffer(int cb) : base(true)
+ {
+ base.SetHandle(Marshal.AllocHGlobal(cb));
+ }
+ public SafeMemoryBuffer(IntPtr handle) : base(true)
+ {
+ base.SetHandle(handle);
+ }
+
+ [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
+ protected override bool ReleaseHandle()
+ {
+ Marshal.FreeHGlobal(handle);
+ return true;
+ }
+ }
+
+ public class WinINetProxy
+ {
+ private string Connection;
+
+ public string AutoConfigUrl;
+ public bool AutoDetect;
+ public string Proxy;
+ public string ProxyBypass;
+
+ public WinINetProxy(string connection)
+ {
+ Connection = connection;
+ Refresh();
+ }
+
+ public void Refresh()
+ {
+ using (var connFlags = CreateConnOption(NativeHelpers.INTERNET_PER_CONN_OPTION.INTERNET_PER_CONN_FLAGS_UI))
+ using (var autoConfigUrl = CreateConnOption(NativeHelpers.INTERNET_PER_CONN_OPTION.INTERNET_PER_CONN_AUTOCONFIG_URL))
+ using (var server = CreateConnOption(NativeHelpers.INTERNET_PER_CONN_OPTION.INTERNET_PER_CONN_PROXY_SERVER))
+ using (var bypass = CreateConnOption(NativeHelpers.INTERNET_PER_CONN_OPTION.INTERNET_PER_CONN_PROXY_BYPASS))
+ {
+ NativeHelpers.INTERNET_PER_CONN_OPTIONW[] options = new NativeHelpers.INTERNET_PER_CONN_OPTIONW[]
+ {
+ connFlags, autoConfigUrl, server, bypass
+ };
+
+ try
+ {
+ QueryOption(options, Connection);
+ }
+ catch (Win32Exception e)
+ {
+ if (e.NativeErrorCode == 87) // ERROR_INVALID_PARAMETER
+ {
+ // INTERNET_PER_CONN_FLAGS_UI only works for IE8+, try the fallback in case we are still working
+ // with an ancient version.
+ connFlags.dwOption = NativeHelpers.INTERNET_PER_CONN_OPTION.INTERNET_PER_CONN_FLAGS;
+ QueryOption(options, Connection);
+ }
+ else
+ throw;
+ }
+
+ NativeHelpers.PER_CONN_FLAGS flags = (NativeHelpers.PER_CONN_FLAGS)connFlags.Value.dwValue;
+
+ AutoConfigUrl = flags.HasFlag(NativeHelpers.PER_CONN_FLAGS.PROXY_TYPE_AUTO_PROXY_URL)
+ ? Marshal.PtrToStringUni(autoConfigUrl.Value.pszValue) : null;
+ AutoDetect = flags.HasFlag(NativeHelpers.PER_CONN_FLAGS.PROXY_TYPE_AUTO_DETECT);
+ if (flags.HasFlag(NativeHelpers.PER_CONN_FLAGS.PROXY_TYPE_PROXY))
+ {
+ Proxy = Marshal.PtrToStringUni(server.Value.pszValue);
+ ProxyBypass = Marshal.PtrToStringUni(bypass.Value.pszValue);
+ }
+ else
+ {
+ Proxy = null;
+ ProxyBypass = null;
+ }
+ }
+ }
+
+ internal static NativeHelpers.INTERNET_PER_CONN_OPTIONW CreateConnOption(NativeHelpers.INTERNET_PER_CONN_OPTION option)
+ {
+ return new NativeHelpers.INTERNET_PER_CONN_OPTIONW
+ {
+ dwOption = option,
+ Value = new NativeHelpers.INTERNET_PER_CONN_OPTIONW.ValueUnion(),
+ };
+ }
+
+ internal static void QueryOption(NativeHelpers.INTERNET_PER_CONN_OPTIONW[] options, string connection = null)
+ {
+ using (NativeHelpers.INTERNET_PER_CONN_OPTION_LISTW optionList = new NativeHelpers.INTERNET_PER_CONN_OPTION_LISTW())
+ using (SafeMemoryBuffer optionListPtr = MarshalOptionList(optionList, options, connection))
+ {
+ UInt32 bufferSize = optionList.dwSize;
+ if (!NativeMethods.InternetQueryOptionW(
+ IntPtr.Zero,
+ NativeHelpers.INTERNET_OPTION.INTERNET_OPTION_PER_CONNECTION_OPTION,
+ optionListPtr,
+ ref bufferSize))
+ {
+ throw new Win32Exception();
+ }
+
+ for (int i = 0; i < options.Length; i++)
+ {
+ IntPtr opt = IntPtr.Add(optionList.pOptions, i * Marshal.SizeOf(typeof(NativeHelpers.INTERNET_PER_CONN_OPTIONW)));
+ NativeHelpers.INTERNET_PER_CONN_OPTIONW option = (NativeHelpers.INTERNET_PER_CONN_OPTIONW)Marshal.PtrToStructure(opt,
+ typeof(NativeHelpers.INTERNET_PER_CONN_OPTIONW));
+ options[i].Value = option.Value;
+ option.Value = null; // Stops the GC from freeing the same memory twice
+ }
+ }
+ }
+
+ internal static SafeMemoryBuffer MarshalOptionList(NativeHelpers.INTERNET_PER_CONN_OPTION_LISTW optionList,
+ NativeHelpers.INTERNET_PER_CONN_OPTIONW[] options, string connection)
+ {
+ optionList.pszConnection = Marshal.StringToHGlobalUni(connection);
+ optionList.dwOptionCount = (UInt32)options.Length;
+
+ int optionSize = Marshal.SizeOf(typeof(NativeHelpers.INTERNET_PER_CONN_OPTIONW));
+ optionList.pOptions = Marshal.AllocHGlobal(optionSize * options.Length);
+ for (int i = 0; i < options.Length; i++)
+ {
+ IntPtr option = IntPtr.Add(optionList.pOptions, i * optionSize);
+ Marshal.StructureToPtr(options[i], option, false);
+ }
+
+ SafeMemoryBuffer optionListPtr = new SafeMemoryBuffer((int)optionList.dwSize);
+ Marshal.StructureToPtr(optionList, optionListPtr.DangerousGetHandle(), false);
+ return optionListPtr;
+ }
+ }
+}
+'@
+Add-CSharpType -References $win_inet_invoke -AnsibleModule $module
+
+$proxy = New-Object -TypeName Ansible.WinINetProxyInfo.WinINetProxy -ArgumentList @(, $connection)
+$module.Result.auto_config_url = $proxy.AutoConfigUrl
+$module.Result.auto_detect = $proxy.AutoDetect
+$module.Result.proxy = $proxy.Proxy
+$module.Result.bypass = $proxy.ProxyBypass
+
+$module.ExitJson()
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_inet_proxy/library/win_phonebook_entry.ps1 b/ansible_collections/community/windows/tests/integration/targets/win_inet_proxy/library/win_phonebook_entry.ps1
new file mode 100644
index 000000000..e449af8ea
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_inet_proxy/library/win_phonebook_entry.ps1
@@ -0,0 +1,523 @@
+#!powershell
+
+# Copyright: (c) 2019, Ansible Project
+# 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.AddType
+
+# This is a very basic skeleton of a possible Windows module for managing RAS connections. It is mostly barebones
+# to enable testing for win_inet_proxy but I've done a bit of extra work in the PInvoke space to possible expand
+# sometime in the future.
+
+$spec = @{
+ options = @{
+ device_type = @{
+ type = "str"
+ choices = @("atm", "framerelay", "generic", "rda", "isdn", "modem", "pad",
+ "parallel", "pppoe", "vpn", "serial", "sonet", "sw56", "x25")
+ }
+ device_name = @{ type = "str" }
+ framing_protocol = @{ type = "str"; choices = @("ppp", "ras", "slip") }
+ name = @{ type = "str"; required = $true }
+ options = @{ type = "list" }
+ state = @{ type = "str"; choices = @("absent", "present"); default = "present" }
+ type = @{ type = "str"; choices = @("broadband", "direct", "phone", "vpn") }
+ }
+ required_if = @(
+ , @("state", "present", @("type", "device_name", "device_type", "framing_protocol"))
+ )
+ supports_check_mode = $false
+}
+
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
+
+$device_type = $module.Params.device_type
+$device_name = $module.Params.device_name
+$framing_protocol = $module.Params.framing_protocol
+$name = $module.Params.name
+$options = $module.Params.options
+$state = $module.Params.state
+$type = $module.Params.type
+
+$module.Result.guid = [System.Guid]::Empty
+
+$win_ras_invoke = @'
+using System;
+using System.Runtime.InteropServices;
+
+namespace Ansible.WinPhonebookEntry
+{
+ public class NativeHelpers
+ {
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ public class RASENTRYW
+ {
+ public UInt32 dwSize;
+ public RasEntryOptions dwfOptions;
+ public UInt32 dwCountryId;
+ public UInt32 dwCountryCode;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)] public string szAreaCode;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 129)] public string szLocalPhoneNumber;
+ public UInt32 dwAlternateOffset;
+ public RASIPADDR ipaddr;
+ public RASIPADDR ipaddrDns;
+ public RASIPADDR ipaddrDnsAlt;
+ public RASIPADDR ipaddrWins;
+ public RASIPADDR ipaddrWinsAlt;
+ public UInt32 dwFrameSize;
+ public RasNetProtocols dwfNetProtocols;
+ public RasFramingProtocol dwFramingProtocol;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string szScript;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string szAutodialDll;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string szAutodialFunc;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)] public string szDeviceType;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 129)] public string szDeviceName;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 33)] public string szX25PadType;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 201)] public string szX25Address;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 201)] public string szX25Facilities;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 201)] public string szX25UserData;
+ public UInt32 dwChannels;
+ public UInt32 dwReserved1;
+ public UInt32 dwReserved2;
+ public UInt32 dwSubEntries;
+ public RasDialMode dwDialMode;
+ public UInt32 dwDialExtraPercent;
+ public UInt32 dwDialExtraSampleSeconds;
+ public UInt32 dwHangUpExtraPercent;
+ public UInt32 dwHangUpExtraSampleSeconds;
+ public UInt32 dwIdleDisconnectSeconds;
+ public RasEntryTypes dwType;
+ public RasEntryEncryption dwEntryptionType;
+ public UInt32 dwCustomAuthKey;
+ public Guid guidId;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string szCustomDialDll;
+ public RasVpnStrategy dwVpnStrategy;
+ public RasEntryOptions2 dwfOptions2;
+ public UInt32 dwfOptions3;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string szDnsSuffix;
+ public UInt32 dwTcpWindowSize;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string szPrerequisitePbk;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 257)] public string szPrerequisiteEntry;
+ public UInt32 dwRedialCount;
+ public UInt32 dwRedialPause;
+ public RASIPV6ADDR ipv6addrDns;
+ public RASIPV6ADDR ipv6addrDnsAlt;
+ public UInt32 dwIPv4InterfaceMatrix;
+ public UInt32 dwIPv6InterfaceMatrix;
+ // Server 2008 R2 / Windows 7+
+ // We cannot include these fields when running in Server 2008 as it will break the SizeOf calc of the struct
+#if !LONGHORN
+ public RASIPV6ADDR ipv6addr;
+ public UInt32 dwIPv6PrefixLength;
+ public UInt32 dwNetworkOutageTime;
+#endif
+
+ public RASENTRYW()
+ {
+ this.dwSize = (UInt32)Marshal.SizeOf(this);
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct RASIPADDR
+ {
+ public byte a;
+ public byte b;
+ public byte c;
+ public byte d;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct RASIPV6ADDR
+ {
+ byte a;
+ byte b;
+ byte c;
+ byte d;
+ byte e;
+ byte f;
+ byte g;
+ byte h;
+ byte i;
+ byte j;
+ byte k;
+ byte l;
+ byte m;
+ byte n;
+ byte o;
+ byte p;
+ }
+
+ public enum RasDialMode : uint
+ {
+ RASEDM_DialAll = 1,
+ RASEDM_DialAsNeeded = 2,
+ }
+
+ public enum RasEntryEncryption : uint
+ {
+ ET_None = 0,
+ ET_Require = 1,
+ ET_RequireMax = 2,
+ ET_Optional = 3
+ }
+
+ [Flags]
+ public enum RasEntryOptions : uint
+ {
+ RASEO_UseCountryAndAreaCodes = 0x00000001,
+ RASEO_SpecificIpAddr = 0x00000002,
+ RASEO_SpecificNameServers = 0x00000004,
+ RASEO_IpHeaderCompression = 0x00000008,
+ RASEO_RemoteDefaultGateway = 0x00000010,
+ RASEO_DisableLcpExtensions = 0x00000020,
+ RASEO_TerminalBeforeDial = 0x00000040,
+ RASEO_TerminalAfterDial = 0x00000080,
+ RASEO_ModemLights = 0x00000100,
+ RASEO_SwCompression = 0x00000200,
+ RASEO_RequireEncrptedPw = 0x00000400,
+ RASEO_RequireMsEncrptedPw = 0x00000800,
+ RASEO_RequireDataEncrption = 0x00001000,
+ RASEO_NetworkLogon = 0x00002000,
+ RASEO_UseLogonCredentials = 0x00004000,
+ RASEO_PromoteAlternates = 0x00008000,
+ RASEO_SecureLocalFiles = 0x00010000,
+ RASEO_RequireEAP = 0x00020000,
+ RASEO_RequirePAP = 0x00040000,
+ RASEO_RequireSPAP = 0x00080000,
+ RASEO_Custom = 0x00100000,
+ RASEO_PreviewPhoneNumber = 0x00200000,
+ RASEO_SharedPhoneNumbers = 0x00800000,
+ RASEO_PreviewUserPw = 0x01000000,
+ RASEO_PreviewDomain = 0x02000000,
+ RASEO_ShowDialingProgress = 0x04000000,
+ RASEO_RequireCHAP = 0x08000000,
+ RASEO_RequireMsCHAP = 0x10000000,
+ RASEO_RequireMsCHAP2 = 0x20000000,
+ RASEO_RequireW95MSCHAP = 0x40000000,
+ RASEO_CustomScript = 0x80000000,
+ }
+
+ [Flags]
+ public enum RasEntryOptions2 : uint
+ {
+ RASEO2_None = 0x00000000,
+ RASEO2_SecureFileAndPrint = 0x00000001,
+ RASEO2_SecureClientForMSNet = 0x00000002,
+ RASEO2_DontNegotiateMultilink = 0x00000004,
+ RASEO2_DontUseRasCredentials = 0x00000008,
+ RASEO2_UsePreSharedKey = 0x00000010,
+ RASEO2_Internet = 0x00000020,
+ RASEO2_DisableNbtOverIP = 0x00000040,
+ RASEO2_UseGlobalDeviceSettings = 0x00000080,
+ RASEO2_ReconnectIfDropped = 0x00000100,
+ RASEO2_SharePhoneNumbers = 0x00000200,
+ RASEO2_SecureRoutingCompartment = 0x00000400,
+ RASEO2_UseTypicalSettings = 0x00000800,
+ RASEO2_IPv6SpecificNameServers = 0x00001000,
+ RASEO2_IPv6RemoteDefaultGateway = 0x00002000,
+ RASEO2_RegisterIpWithDNS = 0x00004000,
+ RASEO2_UseDNSSuffixForRegistration = 0x00008000,
+ RASEO2_IPv4ExplicitMetric = 0x00010000,
+ RASEO2_IPv6ExplicitMetric = 0x00020000,
+ RASEO2_DisableIKENameEkuCheck = 0x00040000,
+ // Server 2008 R2 / Windows 7+
+ RASEO2_DisableClassBasedStaticRoute = 0x00800000,
+ RASEO2_SpecificIPv6Addr = 0x01000000,
+ RASEO2_DisableMobility = 0x02000000,
+ RASEO2_RequireMachineCertificates = 0x04000000,
+ // Server 2012 / Windows 8+
+ RASEO2_UsePreSharedKeyForIkev2Initiator = 0x00800000,
+ RASEO2_UsePreSharedKeyForIkev2Responder = 0x01000000,
+ RASEO2_CacheCredentials = 0x02000000,
+ // Server 2012 R2 / Windows 8.1+
+ RASEO2_AutoTriggerCapable = 0x04000000,
+ RASEO2_IsThirdPartyProfile = 0x08000000,
+ RASEO2_AuthTypeIsOtp = 0x10000000,
+ // Server 2016 / Windows 10+
+ RASEO2_IsAlwaysOn = 0x20000000,
+ RASEO2_IsPrivateNetwork = 0x40000000,
+ }
+
+ public enum RasEntryTypes : uint
+ {
+ RASET_Phone = 1,
+ RASET_Vpn = 2,
+ RASET_Direct = 3,
+ RASET_Internet = 4,
+ RASET_Broadband = 5,
+ }
+
+ public enum RasFramingProtocol : uint
+ {
+ RASFP_Ppp = 0x00000001,
+ RASFP_Slip = 0x00000002,
+ RASFP_Ras = 0x00000004
+ }
+
+ [Flags]
+ public enum RasNetProtocols : uint
+ {
+ RASNP_NetBEUI = 0x00000001,
+ RASNP_Ipx = 0x00000002,
+ RASNP_Ip = 0x00000004,
+ RASNP_Ipv6 = 0x00000008
+ }
+
+ public enum RasVpnStrategy : uint
+ {
+ VS_Default = 0,
+ VS_PptpOnly = 1,
+ VS_PptpFirst = 2,
+ VS_L2tpOnly = 3,
+ VS_L2tpFirst = 4,
+ VS_SstpOnly = 5,
+ VS_SstpFirst = 6,
+ VS_Ikev2Only = 7,
+ VS_Ikev2First = 8,
+ VS_GREOnly = 9,
+ VS_PptpSstp = 12,
+ VS_L2tpSstp = 13,
+ VS_Ikev2Sstp = 14,
+ }
+ }
+
+ internal class NativeMethods
+ {
+ [DllImport("Rasapi32.dll", CharSet = CharSet.Unicode)]
+ public static extern UInt32 RasDeleteEntryW(
+ string lpszPhonebook,
+ string lpszEntry);
+
+ [DllImport("Rasapi32.dll", CharSet = CharSet.Unicode)]
+ public static extern UInt32 RasGetEntryPropertiesW(
+ string lpszPhonebook,
+ string lpszEntry,
+ [In, Out] NativeHelpers.RASENTRYW lpRasEntry,
+ ref UInt32 dwEntryInfoSize,
+ IntPtr lpbDeviceInfo,
+ ref UInt32 dwDeviceInfoSize);
+
+ [DllImport("Rasapi32.dll", CharSet = CharSet.Unicode)]
+ public static extern UInt32 RasSetEntryPropertiesW(
+ string lpszPhonebook,
+ string lpszEntry,
+ NativeHelpers.RASENTRYW lpRasEntry,
+ UInt32 dwEntryInfoSize,
+ IntPtr lpbDeviceInfo,
+ UInt32 dwDeviceInfoSize);
+
+ [DllImport("Rasapi32.dll", CharSet = CharSet.Unicode)]
+ public static extern UInt32 RasValidateEntryNameW(
+ string lpszPhonebook,
+ string lpszEntry);
+ }
+
+ public class Phonebook
+ {
+ public static void CreateEntry(string entry, NativeHelpers.RASENTRYW details)
+ {
+ UInt32 res = NativeMethods.RasSetEntryPropertiesW(null, entry, details,
+ details.dwSize, IntPtr.Zero, 0);
+
+ if (res != 0)
+ throw new Exception(String.Format("RasSetEntryPropertiesW({0}) failed {1}", entry, res));
+ }
+
+ public static void DeleteEntry(string entry)
+ {
+ UInt32 res = NativeMethods.RasDeleteEntryW(null, entry);
+ if (res != 0)
+ throw new Exception(String.Format("RasDeleteEntryW({0}) failed {1}", entry, res));
+ }
+
+ public static NativeHelpers.RASENTRYW GetEntry(string entry)
+ {
+ NativeHelpers.RASENTRYW details = new NativeHelpers.RASENTRYW();
+ UInt32 dwEntryInfoSize = details.dwSize;
+ UInt32 dwDeviceInfoSize = 0;
+
+ UInt32 res = NativeMethods.RasGetEntryPropertiesW(null, entry, details, ref dwEntryInfoSize,
+ IntPtr.Zero, ref dwDeviceInfoSize);
+
+ if (res != 0)
+ throw new Exception(String.Format("RasGetEntryPropertiesW({0}) failed {1}", entry, res));
+
+ return details;
+ }
+
+ public static bool IsValidEntry(string entry)
+ {
+ // 183 == ENTRY_ALREADY_EXISTS
+ return NativeMethods.RasValidateEntryNameW(null, entry) == 183;
+ }
+ }
+}
+'@
+
+$add_type_params = @{
+ Reference = $win_ras_invoke
+ AnsibleModule = $module
+}
+# We need to set a custom compile option when running on Server 2008 due to the change in the RASENTRYW structure
+$os_version = [Version](Get-Item -LiteralPath $env:SystemRoot\System32\kernel32.dll).VersionInfo.ProductVersion
+if ($os_version -lt [Version]"6.1") {
+ $add_type_params.CompileSymbols = @("LONGHORN")
+}
+Add-CSharpType @add_type_params
+
+$exists = [Ansible.WinPhonebookEntry.Phonebook]::IsValidEntry($name)
+if ($exists) {
+ $entry = [Ansible.WinPhonebookEntry.Phonebook]::GetEntry($name)
+ $module.Result.guid = $entry.guidId
+}
+
+if ($state -eq "present") {
+ # Convert the input values to enum values
+ $expected_type = switch ($type) {
+ "broadband" { [Ansible.WinPhonebookEntry.NativeHelpers+RasEntryTypes]::RASET_Broadband }
+ "direct" { [Ansible.WinPhonebookEntry.NativeHelpers+RasEntryTypes]::RASET_Direct }
+ "phone" { [Ansible.WinPhonebookEntry.NativeHelpers+RasEntryTypes]::RASET_Phone }
+ "vpn" { [Ansible.WinPhonebookEntry.NativeHelpers+RasEntryTypes]::RASET_Vpn }
+ }
+
+ $expected_framing_protocol = switch ($framing_protocol) {
+ "ppp" { [Ansible.WinPhonebookEntry.NativeHelpers+RasFramingProtocol]::RASFP_Ppp }
+ "ras" { [Ansible.WinPhonebookEntry.NativeHelpers+RasFramingProtocol]::RASFP_Ras }
+ "slip" { [Ansible.WinPhonebookEntry.NativeHelpers+RasFramingProtocol]::RASFP_Slip }
+ }
+
+ $expected_options1 = [System.Collections.Generic.List`1[String]]@()
+ $expected_options2 = [System.Collections.Generic.List`1[String]]@()
+ $invalid_options = [System.Collections.Generic.List`1[String]]@()
+ foreach ($option in $options) {
+ # See https://msdn.microsoft.com/en-us/25c46850-4fb7-47a9-9645-139f0e869559 for more info on the options
+ # TODO: some of these options are set to indicate entries in RASENTRYW, we should automatically add them
+ # based on the input values.
+ switch ($option) {
+ # dwfOptions
+ "use_country_and_area_codes" { $expected_options1.Add("RASEO_UseCountryAndAreaCode") }
+ "specific_ip_addr" { $expected_options1.Add("RASEO_SpecificIpAddr") }
+ "specific_name_servers" { $expected_options1.Add("RASEO_SpecificNameServers") }
+ "ip_header_compression" { $expected_options1.Add("RASEO_IpHeaderCompression") }
+ "remote_default_gateway" { $expected_options1.Add("RASEO_RemoteDefaultGateway") }
+ "disable_lcp_extensions" { $expected_options1.Add("RASEO_DisableLcpExtensions") }
+ "terminal_before_dial" { $expected_options1.Add("RASEO_TerminalBeforeDial") }
+ "terminal_after_dial" { $expected_options1.Add("RASEO_TerminalAfterDial") }
+ "modem_lights" { $expected_options1.Add("RASEO_ModemLights") }
+ "sw_compression" { $expected_options1.Add("RASEO_SwCompression") }
+ "require_encrypted_password" { $expected_options1.Add("RASEO_RequireEncrptedPw") }
+ "require_ms_encrypted_password" { $expected_options1.Add("RASEO_RequireMsEncrptedPw") }
+ "require_data_encryption" { $expected_options1.Add("RASEO_RequireDataEncrption") }
+ "network_logon" { $expected_options1.Add("RASEO_NetworkLogon") }
+ "use_logon_credentials" { $expected_options1.Add("RASEO_UseLogonCredentials") }
+ "promote_alternates" { $expected_options1.Add("RASEO_PromoteAlternates") }
+ "secure_local_files" { $expected_options1.Add("RASEO_SecureLocalFiles") }
+ "require_eap" { $expected_options1.Add("RASEO_RequireEAP") }
+ "require_pap" { $expected_options1.Add("RASEO_RequirePAP") }
+ "require_spap" { $expected_options1.Add("RASEO_RequireSPAP") }
+ "custom" { $expected_options1.Add("RASEO_Custom") }
+ "preview_phone_number" { $expected_options1.Add("RASEO_PreviewPhoneNumber") }
+ "shared_phone_numbers" { $expected_options1.Add("RASEO_SharedPhoneNumbers") }
+ "preview_user_password" { $expected_options1.Add("RASEO_PreviewUserPw") }
+ "preview_domain" { $expected_options1.Add("RASEO_PreviewDomain") }
+ "show_dialing_progress" { $expected_options1.Add("RASEO_ShowDialingProgress") }
+ "require_chap" { $expected_options1.Add("RASEO_RequireCHAP") }
+ "require_ms_chap" { $expected_options1.Add("RASEO_RequireMsCHAP") }
+ "require_ms_chap2" { $expected_options1.Add("RASEO_RequireMsCHAP2") }
+ "require_w95_ms_chap" { $expected_options1.Add("RASEO_RequireW95MSCHAP") }
+ "custom_script" { $expected_options1.Add("RASEO_CustomScript") }
+ # dwfOptions2
+ "secure_file_and_print" { $expected_options2.Add("RASEO2_SecureFileAndPrint") }
+ "secure_client_for_ms_net" { $expected_options2.Add("RASEO2_SecureClientForMSNet") }
+ "dont_negotiate_multilink" { $expected_options2.Add("RASEO2_DontNegotiateMultilink") }
+ "dont_use_ras_credential" { $expected_options2.Add("RASEO2_DontUseRasCredentials") }
+ "use_pre_shared_key" { $expected_options2.Add("RASEO2_UsePreSharedKey") }
+ "internet" { $expected_options2.Add("RASEO2_Internet") }
+ "disable_nbt_over_ip" { $expected_options2.Add("RASEO2_DisableNbtOverIP") }
+ "use_global_device_settings" { $expected_options2.Add("RASEO2_UseGlobalDeviceSettings") }
+ "reconnect_if_dropped" { $expected_options2.Add("RASEO2_ReconnectIfDropped") }
+ "share_phone_numbers" { $expected_options2.Add("RASEO2_SharePhoneNumbers") }
+ "secure_routing_compartment" { $expected_options2.Add("RASEO2_SecureRoutingCompartment") }
+ "use_typical_settings" { $expected_options2.Add("RASEO2_UseTypicalSettings") }
+ "ipv6_specific_name_servers" { $expected_options2.Add("RASEO2_IPv6SpecificNameServers") }
+ "ipv6_remote_default_gateway" { $expected_options2.Add("RASEO2_IPv6RemoteDefaultGateway") }
+ "register_ip_with_dns" { $expected_options2.Add("RASEO2_RegisterIpWithDNS") }
+ "use_dns_suffix_for_registration" { $expected_options2.Add("RASEO2_UseDNSSuffixForRegistration") }
+ "ipv4_explicit_metric" { $expected_options2.Add("RASEO2_IPv4ExplicitMetric") }
+ "ipv6_explicit_metric" { $expected_options2.Add("RASEO2_IPv6ExplicitMetric") }
+ "disable_ike_name_eku_check" { $expected_options2.Add("RASEO2_DisableIKENameEkuCheck") }
+ # TODO: Version check for the below, OS Version >= 6.1
+ "disable_class_based_static_route" { $expected_options2.Add("RASEO2_DisableClassBasedStaticRoute") }
+ "specific_ipv6_addr" { $expected_options2.Add("RASEO2_SpecificIPv6Addr") }
+ "disable_mobility" { $expected_options2.Add("RASEO2_DisableMobility") }
+ "require_machine_certificates" { $expected_options2.Add("RASEO2_RequireMachineCertificates") }
+ # TODO: Version check for the below, OS Version >= 6.2
+ "use_pre_shared_key_for_ikev2_initiator" { $expected_options2.Add("RASEO2_UsePreSharedKeyForIkev2Initiator") }
+ "use_pre_shared_key_for_ikev2_responder" { $expected_options2.Add("RASEO2_UsePreSharedKeyForIkev2Responder") }
+ "cache_credentials" { $expected_options2.Add("RASEO2_CacheCredentials") }
+ # TODO: Version check for the below, OS Version >= 6.3
+ "auto_trigger_capable" { $expected_options2.Add("RASEO2_AutoTriggerCapable") }
+ "is_third_party_profile" { $expected_options2.Add("RASEO2_IsThirdPartyProfile") }
+ "auth_type_is_otp" { $expected_options2.Add("RASEO2_AuthTypeIsOtp") }
+ # TODO: Version check for the below, OS Version >= 10.0
+ "is_always_on" { $expected_options2.Add("RASEO2_IsAlwaysOn") }
+ "is_private_network" { $expected_options2.Add("RASEO2_IsPrivateNetwork") }
+ default { $invalid_options.Add($option) }
+ }
+ }
+ if ($invalid_options.Count -gt 0) {
+ $module.FailJson("Encountered invalid options: $($invalid_options -join ", ")")
+ }
+ $expected_options1 = [Ansible.WinPhonebookEntry.NativeHelpers+RasEntryOptions]($expected_options1 -join ", ")
+ $expected_options2 = [Ansible.WinPhonebookEntry.NativeHelpers+RasEntryOptions2]($expected_options2 -join ", ")
+
+ $property_map = @{
+ szDeviceName = $device_name
+ szDeviceType = $device_type
+ dwFramingProtocol = $expected_framing_protocol
+ dwfOptions = $expected_options1
+ dwfOptions2 = $expected_options2
+ dwType = $expected_type
+ }
+
+ if (-not $exists) {
+ $entry = New-Object -TypeName Ansible.WinPhonebookEntry.NativeHelpers+RASENTRYW
+ foreach ($kvp in $property_map.GetEnumerator()) {
+ $entry."$($kvp.Key)" = $kvp.Value
+ }
+
+ [Ansible.WinPhonebookEntry.Phonebook]::CreateEntry($name, $entry)
+ $module.Result.changed = $true
+
+ # Once created we then get the entry object again to retrieve the unique GUID ID to return
+ $entry = [Ansible.WinPhonebookEntry.Phonebook]::GetEntry($name)
+ $module.Result.guid = $entry.guidId
+ }
+ else {
+ $entry = [Ansible.WinPhonebookEntry.Phonebook]::GetEntry($name)
+ $changed = $false
+ foreach ($kvp in $property_map.GetEnumerator()) {
+ $key = $kvp.Key
+ $actual_value = $entry.$key
+ if ($actual_value -ne $kvp.Value) {
+ $entry.$key = $kvp.Value
+ $changed = $true
+ }
+ }
+
+ if ($changed) {
+ [Ansible.WinPhonebookEntry.Phonebook]::CreateEntry($name, $entry)
+ $module.Result.changed = $true
+ }
+ }
+}
+else {
+ if ($exists) {
+ [Ansible.WinPhonebookEntry.Phonebook]::DeleteEntry($name)
+ $module.Result.changed = $true
+ }
+}
+
+$module.ExitJson()
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_inet_proxy/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_inet_proxy/tasks/main.yml
new file mode 100644
index 000000000..f92a60eab
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_inet_proxy/tasks/main.yml
@@ -0,0 +1,16 @@
+---
+- name: make sure we start the tests with the defaults
+ win_inet_proxy:
+
+- block:
+ - name: run tests
+ include_tasks: tests.yml
+
+ always:
+ - name: reset proxy back to defaults
+ win_inet_proxy:
+
+ - name: remove phonebook entry
+ win_phonebook_entry:
+ name: Ansible Test Dialup
+ state: absent
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_inet_proxy/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_inet_proxy/tasks/tests.yml
new file mode 100644
index 000000000..47ddfbe2e
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_inet_proxy/tasks/tests.yml
@@ -0,0 +1,308 @@
+---
+- name: ensure we fail when proxy is not set with bypass
+ win_inet_proxy:
+ bypass: abc
+ register: fail_bypass
+ failed_when: 'fail_bypass.msg != "missing parameter(s) required by ''bypass'': proxy"'
+
+- name: ensure we fail if an invalid protocol is specified
+ win_inet_proxy:
+ proxy:
+ fail1: fail
+ fail2: fail
+ register: fail_proxy
+ failed_when: 'fail_proxy.msg != "Invalid keys found in proxy: fail1, fail2. Valid keys are http, https, ftp, socks."'
+
+- name: ensure we fail if invalid value is set
+ win_inet_proxy:
+ proxy: fake=proxy
+ register: fail_invalid
+ failed_when: fail_invalid.msg != "Unknown error when trying to set auto_config_url '', proxy 'fake=proxy', or bypass ''"
+
+- name: ensure we fail if an invalid connection is set
+ win_inet_proxy:
+ connection: Fake Connection
+ register: fail_connection
+ failed_when: fail_connection.msg != "The connection 'Fake Connection' does not exist."
+
+- name: check proxy is still set to Direct access
+ win_inet_proxy_info:
+ register: fail_invalid_actual
+ failed_when: fail_invalid_actual.proxy == 'fake=proxy'
+
+- name: disable auto detect (check)
+ win_inet_proxy:
+ auto_detect: no
+ register: disable_auto_detect_check
+ check_mode: yes
+
+- name: get result of disable auto detect (check)
+ win_inet_proxy_info:
+ register: disable_auto_detect_actual_check
+
+- name: assert disable auto detect (check)
+ assert:
+ that:
+ - disable_auto_detect_check is changed
+ - disable_auto_detect_actual_check.auto_detect
+
+- name: disable auto detect
+ win_inet_proxy:
+ auto_detect: no
+ register: disable_auto_detect
+
+- name: get result of disable auto detect
+ win_inet_proxy_info:
+ register: disable_auto_detect_actual
+
+- name: assert disable auto detect
+ assert:
+ that:
+ - disable_auto_detect is changed
+ - not disable_auto_detect_actual.auto_detect
+
+- name: disable auto detect (idempotent)
+ win_inet_proxy:
+ auto_detect: no
+ register: disable_auto_detect_again
+
+- name: assert disable auto detect (idempotent)
+ assert:
+ that:
+ - not disable_auto_detect_again is changed
+
+- name: set auto config url
+ win_inet_proxy:
+ auto_config_url: http://ansible.com/proxy.pac
+ register: set_auto_url
+
+- name: get result of set auto config url
+ win_inet_proxy_info:
+ register: set_auto_url_actual
+
+- name: assert set auto config url
+ assert:
+ that:
+ - set_auto_url is changed
+ - set_auto_url_actual.auto_detect
+ - set_auto_url_actual.auto_config_url == 'http://ansible.com/proxy.pac'
+
+- name: set auto config url (idempotent)
+ win_inet_proxy:
+ auto_config_url: http://ansible.com/proxy.pac
+ register: set_auto_url_again
+
+- name: set auto config url (idempotent)
+ assert:
+ that:
+ - not set_auto_url_again is changed
+
+- name: set a proxy using a string
+ win_inet_proxy:
+ proxy: proxyhost
+ register: proxy_str
+
+- name: get result of set a proxy using a string
+ win_inet_proxy_info:
+ register: proxy_str_actual
+
+- name: assert set a proxy using a string
+ assert:
+ that:
+ - proxy_str is changed
+ - proxy_str_actual.auto_detect
+ - proxy_str_actual.auto_config_url == None
+ - proxy_str_actual.proxy == 'proxyhost'
+
+- name: set a proxy using a string (idempotent)
+ win_inet_proxy:
+ proxy: proxyhost
+ register: proxy_str_again
+
+- name: assert set a proxy using a string (idempotent)
+ assert:
+ that:
+ - not proxy_str_again is changed
+
+- name: change a proxy and set bypass
+ win_inet_proxy:
+ proxy: proxyhost:8080
+ bypass:
+ - abc
+ - def
+ - <local>
+ register: change_proxy
+
+- name: get result of change a proxy and set bypass
+ win_inet_proxy_info:
+ register: change_proxy_actual
+
+- name: assert change a proxy and set bypass
+ assert:
+ that:
+ - change_proxy is changed
+ - change_proxy_actual.proxy == 'proxyhost:8080'
+ - change_proxy_actual.bypass == 'abc;def;<local>'
+
+- name: change a proxy and set bypass (idempotent)
+ win_inet_proxy:
+ proxy: proxyhost:8080
+ bypass: abc,def,<local>
+ register: change_proxy_again
+
+- name: assert change a proxy and set bypass (idempotent)
+ assert:
+ that:
+ - not change_proxy_again is changed
+
+- name: change bypass list
+ win_inet_proxy:
+ proxy: proxyhost:8080
+ bypass:
+ - abc
+ - <-loopback>
+ register: change_bypass
+
+- name: get reuslt of change bypass list
+ win_inet_proxy_info:
+ register: change_bypass_actual
+
+- name: assert change bypass list
+ assert:
+ that:
+ - change_bypass is changed
+ - change_bypass_actual.proxy == 'proxyhost:8080'
+ - change_bypass_actual.bypass == 'abc;<-loopback>'
+
+- name: remove proxy without options
+ win_inet_proxy:
+ register: remove_proxy
+
+- name: get result of remove proxy without options
+ win_inet_proxy_info:
+ register: remove_proxy_actual
+
+- name: assert remove proxy without options
+ assert:
+ that:
+ - remove_proxy is changed
+ - remove_proxy_actual.auto_detect == True
+ - remove_proxy_actual.auto_config_url == None
+ - remove_proxy_actual.proxy == None
+ - remove_proxy_actual.bypass == None
+
+- name: remove proxy without options (idempotent)
+ win_inet_proxy:
+ register: remove_proxy_again
+
+- name: assert remove proxy without options (idempotent)
+ assert:
+ that:
+ - not remove_proxy_again is changed
+
+- name: set proxy with dictionary
+ win_inet_proxy:
+ proxy:
+ http: proxy:8080
+ https: proxy:8443
+ ftp: proxy:821
+ socks: proxy:888
+ register: set_dict
+
+- name: get result of set proxy with dictionary
+ win_inet_proxy_info:
+ register: set_dict_actual
+
+- name: assert set proxy with dictionary
+ assert:
+ that:
+ - set_dict is changed
+ - set_dict_actual.proxy == 'http=proxy:8080;https=proxy:8443;ftp=proxy:821;socks=proxy:888'
+
+- name: set proxy protocol with str
+ win_inet_proxy:
+ proxy: http=proxy:8080;https=proxy:8443;ftp=proxy:821;socks=proxy:888
+ register: set_str_protocol
+
+- name: assert set proxy protocol with str
+ assert:
+ that:
+ - not set_str_protocol is changed
+
+- name: remove proxy with empty string
+ win_inet_proxy:
+ proxy: ''
+ register: remove_empty_str
+
+- name: get result of remove proxy with empty string
+ win_inet_proxy_info:
+ register: remove_empty_str_actual
+
+- name: assert remove proxy with empty string
+ assert:
+ that:
+ - remove_empty_str is changed
+ - remove_empty_str_actual.proxy == None
+
+- name: create test phonebook entry
+ win_phonebook_entry:
+ name: Ansible Test Dialup
+ device_type: pppoe
+ device_name: WAN Miniport (PPPOE)
+ framing_protocol: ppp
+ options:
+ - remote_default_gateway
+ - require_pap
+ - internet
+ type: broadband
+ state: present
+
+- name: set proxy for specific connection
+ win_inet_proxy:
+ connection: Ansible Test Dialup
+ auto_detect: no
+ auto_config_url: proxy.com
+ proxy: proxyhost:8080
+ bypass: proxyhost
+ register: set_connection
+
+- name: get result for set proxy for specific connection
+ win_inet_proxy_info:
+ connection: Ansible Test Dialup
+ register: set_connection_actual
+
+- name: get result for LAN connection proxy
+ win_inet_proxy_info:
+ register: set_connection_lan_actual
+
+- name: assert set proxy for specific connection
+ assert:
+ that:
+ - set_connection is changed
+ - set_connection_actual.auto_detect == False
+ - set_connection_actual.auto_config_url == 'proxy.com'
+ - set_connection_actual.proxy == 'proxyhost:8080'
+ - set_connection_actual.bypass == 'proxyhost'
+ - set_connection_lan_actual.auto_detect == True
+ - set_connection_lan_actual.auto_config_url == None
+ - set_connection_lan_actual.proxy == None
+ - set_connection_lan_actual.bypass == None
+
+- name: remove proxy for specific connection
+ win_inet_proxy:
+ connection: Ansible Test Dialup
+ register: remove_connection
+
+- name: get result of remove proxy for specific connection
+ win_inet_proxy_info:
+ connection: Ansible Test Dialup
+ register: remove_connection_actual
+
+- name: assert remove proxy for specific connection
+ assert:
+ that:
+ - remove_connection is changed
+ - remove_connection_actual.auto_detect == True
+ - remove_connection_actual.auto_config_url == None
+ - remove_connection_actual.proxy == None
+ - remove_connection_actual.bypass == None
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_initialize_disk/aliases b/ansible_collections/community/windows/tests/integration/targets/win_initialize_disk/aliases
new file mode 100644
index 000000000..4f4664b68
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_initialize_disk/aliases
@@ -0,0 +1 @@
+shippable/windows/group5
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_initialize_disk/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_initialize_disk/defaults/main.yml
new file mode 100644
index 000000000..9cb54a30c
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_initialize_disk/defaults/main.yml
@@ -0,0 +1 @@
+AnsibleVhdx: C:\win_initialize_disk_tests\AnsiblePart.vhdx
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_initialize_disk/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_initialize_disk/tasks/main.yml
new file mode 100644
index 000000000..b752a7913
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_initialize_disk/tasks/main.yml
@@ -0,0 +1,28 @@
+---
+- name: Create the temp directory
+ ansible.windows.win_file:
+ path: C:\win_initialize_disk_tests
+ state: directory
+
+- name: Copy VHDX scripts
+ ansible.windows.win_template:
+ src: "{{ item.src }}"
+ dest: C:\win_initialize_disk_tests\{{ item.dest }}
+ loop:
+ - { src: vhdx_creation_script.j2, dest: vhdx_creation_script.txt }
+ - { src: vhdx_deletion_script.j2, dest: vhdx_deletion_script.txt }
+
+- name: Create VHD
+ ansible.windows.win_command: diskpart.exe /s C:\win_initialize_disk_tests\vhdx_creation_script.txt
+
+- name: Run tests
+ block:
+ - include: tests.yml
+ always:
+ - name: Detach disk
+ ansible.windows.win_command: diskpart.exe /s C:\win_initialize_disk_tests\vhdx_deletion_script.txt
+
+ - name: Cleanup files
+ ansible.windows.win_file:
+ path: C:\win_initialize_disk_tests
+ state: absent
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_initialize_disk/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_initialize_disk/tasks/tests.yml
new file mode 100644
index 000000000..b9bc1d70b
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_initialize_disk/tasks/tests.yml
@@ -0,0 +1,104 @@
+---
+- name: Initialize the disk with the default partition style (check mode)
+ win_initialize_disk:
+ disk_number: 1
+ register: default_part_style_check
+ check_mode: yes
+
+- name: Get result of default initialization (check mode)
+ ansible.windows.win_command: powershell.exe "if ( (Get-Disk -Number 1).PartitionStyle -eq 'RAW' ) {'true'} else {'false'}"
+ register: default_part_style_actual_check
+
+- name: assert default initialization (check mode)
+ assert:
+ that:
+ - default_part_style_check is changed
+ - default_part_style_actual_check.stdout == 'true\r\n'
+
+- name: Initialize the disk with the default partition style
+ win_initialize_disk:
+ disk_number: 1
+ register: default_part_style
+
+- name: Get result of default initialization
+ ansible.windows.win_command: powershell.exe "if ( (Get-Disk -Number 1).PartitionStyle -eq 'GPT' ) {'true'} else {'false'}"
+ register: default_part_style_actual
+
+- name: assert default initialization
+ assert:
+ that:
+ - default_part_style is changed
+ - default_part_style_actual.stdout == 'true\r\n'
+
+- name: Initialize the disk with the default partition style (idempotence)
+ win_initialize_disk:
+ disk_number: 1
+ register: default_part_style_idempotence
+
+- name: Get result of default initialization (idempotence)
+ ansible.windows.win_command: powershell.exe "if ( (Get-Disk -Number 1).PartitionStyle -eq 'GPT' ) {'true'} else {'false'}"
+ register: default_part_style_actual_idempotence
+
+- name: assert default initialization (idempotence)
+ assert:
+ that:
+ - not default_part_style_idempotence is changed
+ - default_part_style_actual_idempotence.stdout == 'true\r\n'
+
+- name: Partition style change without force fails
+ win_initialize_disk:
+ disk_number: 1
+ style: mbr
+ register: change_part_style
+ ignore_errors: True
+
+- name: assert failed partition style change
+ assert:
+ that:
+ - change_part_style is failed
+
+- name: Partition style change with force is successful (check mode)
+ win_initialize_disk:
+ disk_number: 1
+ style: mbr
+ force: yes
+ register: change_part_style_forced_check
+ check_mode: yes
+
+- name: Get result of forced initialization (check mode)
+ ansible.windows.win_command: powershell.exe "if ( (Get-Disk -Number 1).PartitionStyle -eq 'GPT' ) {'true'} else {'false'}"
+ register: change_part_style_forced_actual_check
+
+- name: assert forced initialization (check mode)
+ assert:
+ that:
+ - change_part_style_forced_check is changed
+ - change_part_style_forced_actual_check.stdout == 'true\r\n'
+
+- name: Partition style change with force is successful
+ win_initialize_disk:
+ disk_number: 1
+ style: mbr
+ force: yes
+ register: change_part_style_forced
+
+- name: Get result of forced initialization
+ ansible.windows.win_command: powershell.exe "if ( (Get-Disk -Number 1).PartitionStyle -eq 'MBR' ) {'true'} else {'false'}"
+ register: change_part_style_forced_actual
+
+- name: assert forced initialization
+ assert:
+ that:
+ - change_part_style_forced is changed
+ - change_part_style_forced_actual.stdout == 'true\r\n'
+
+- name: Unknown disk number fails
+ win_initialize_disk:
+ disk_number: 3
+ register: unknown_disk_number
+ ignore_errors: True
+
+- name: assert unknown disk number fails
+ assert:
+ that:
+ - unknown_disk_number is failed
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_initialize_disk/templates/vhdx_creation_script.j2 b/ansible_collections/community/windows/tests/integration/targets/win_initialize_disk/templates/vhdx_creation_script.j2
new file mode 100644
index 000000000..4089bf379
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_initialize_disk/templates/vhdx_creation_script.j2
@@ -0,0 +1,5 @@
+create vdisk file="{{ AnsibleVhdx }}" maximum=2000 type=fixed
+
+select vdisk file="{{ AnsibleVhdx }}"
+
+attach vdisk
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_initialize_disk/templates/vhdx_deletion_script.j2 b/ansible_collections/community/windows/tests/integration/targets/win_initialize_disk/templates/vhdx_deletion_script.j2
new file mode 100644
index 000000000..c2be9cd14
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_initialize_disk/templates/vhdx_deletion_script.j2
@@ -0,0 +1,3 @@
+select vdisk file="{{ AnsibleVhdx }}"
+
+detach vdisk
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/aliases b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/aliases
new file mode 100644
index 000000000..4cd27b3cb
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/aliases
@@ -0,0 +1 @@
+shippable/windows/group1
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/.gitattributes b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/.gitattributes
new file mode 100644
index 000000000..d3f27225a
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/.gitattributes
@@ -0,0 +1,4 @@
+*.text text eol=LF
+*.txt text eol=CRLF
+*.txt16 text working-tree-encoding=UTF-16 eol=CRLF
+*.txt32 text working-tree-encoding=UTF-32 eol=CRLF
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/01_new_line_at_bof.txt b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/01_new_line_at_bof.txt
new file mode 100644
index 000000000..01a263dbc
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/01_new_line_at_bof.txt
@@ -0,0 +1,6 @@
+New line at the beginning
+This is line 1
+This is line 2
+REF this is a line for backrefs REF
+This is line 4
+This is line 5
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/02_new_line_at_eof.txt b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/02_new_line_at_eof.txt
new file mode 100644
index 000000000..ff0ffa89d
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/02_new_line_at_eof.txt
@@ -0,0 +1,7 @@
+New line at the beginning
+This is line 1
+This is line 2
+REF this is a line for backrefs REF
+This is line 4
+This is line 5
+New line at the end
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/03_new_line_after_1.txt b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/03_new_line_after_1.txt
new file mode 100644
index 000000000..c13010c68
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/03_new_line_after_1.txt
@@ -0,0 +1,8 @@
+New line at the beginning
+This is line 1
+New line after line 1
+This is line 2
+REF this is a line for backrefs REF
+This is line 4
+This is line 5
+New line at the end
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/04_new_line_before_5.txt b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/04_new_line_before_5.txt
new file mode 100644
index 000000000..9e021050b
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/04_new_line_before_5.txt
@@ -0,0 +1,9 @@
+New line at the beginning
+This is line 1
+New line after line 1
+This is line 2
+REF this is a line for backrefs REF
+This is line 4
+New line before line 5
+This is line 5
+New line at the end
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/05_new_line_at_REF.txt b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/05_new_line_at_REF.txt
new file mode 100644
index 000000000..4a5379ae0
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/05_new_line_at_REF.txt
@@ -0,0 +1,9 @@
+New line at the beginning
+This is line 1
+New line after line 1
+This is line 2
+This is line 3
+This is line 4
+New line before line 5
+This is line 5
+New line at the end
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/06_remove_middle_line.txt b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/06_remove_middle_line.txt
new file mode 100644
index 000000000..bd0e8f595
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/06_remove_middle_line.txt
@@ -0,0 +1,8 @@
+New line at the beginning
+This is line 1
+New line after line 1
+This is line 2
+This is line 4
+New line before line 5
+This is line 5
+New line at the end
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/07_remove_line_5.txt b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/07_remove_line_5.txt
new file mode 100644
index 000000000..ae0b0ab98
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/07_remove_line_5.txt
@@ -0,0 +1,7 @@
+New line at the beginning
+This is line 1
+New line after line 1
+This is line 2
+This is line 4
+New line before line 5
+New line at the end
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/08_no_expected_change.txt b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/08_no_expected_change.txt
new file mode 100644
index 000000000..ae0b0ab98
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/08_no_expected_change.txt
@@ -0,0 +1,7 @@
+New line at the beginning
+This is line 1
+New line after line 1
+This is line 2
+This is line 4
+New line before line 5
+New line at the end
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/09_new_file.txt b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/09_new_file.txt
new file mode 100644
index 000000000..6dfa057f0
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/09_new_file.txt
@@ -0,0 +1 @@
+This is a new file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/10_no_eof_new_at_eof.txt b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/10_no_eof_new_at_eof.txt
new file mode 100644
index 000000000..31b06636a
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/10_no_eof_new_at_eof.txt
@@ -0,0 +1,3 @@
+This is line 1
+This is line 2
+New line at the end \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/11_multiline_at_eof.txt b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/11_multiline_at_eof.txt
new file mode 100644
index 000000000..fa15cdba3
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/11_multiline_at_eof.txt
@@ -0,0 +1,9 @@
+New line at the beginning
+This is line 1
+New line after line 1
+This is line 2
+This is line 4
+New line before line 5
+New line at the end
+This is a line
+with newline character
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/12_empty_file_add_at_eof.txt b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/12_empty_file_add_at_eof.txt
new file mode 100644
index 000000000..1467ce9ea
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/12_empty_file_add_at_eof.txt
@@ -0,0 +1 @@
+New line at the end \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/13_new_4_with_backref.txt b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/13_new_4_with_backref.txt
new file mode 100644
index 000000000..3c86758a0
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/13_new_4_with_backref.txt
@@ -0,0 +1,9 @@
+New line at the beginning
+This is line 1
+New line after line 1
+This is line 2
+New line 4 created with the backref
+New line before line 5
+New line at the end
+This is a line
+with newline character
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/14_quoting_code.txt b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/14_quoting_code.txt
new file mode 100644
index 000000000..3575ba049
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/14_quoting_code.txt
@@ -0,0 +1,3 @@
+var dotenv = require('dotenv');
+dotenv.load();
+'foo' \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/15_single_quote.txt b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/15_single_quote.txt
new file mode 100644
index 000000000..e1e1cf090
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/15_single_quote.txt
@@ -0,0 +1,4 @@
+var dotenv = require('dotenv');
+dotenv.load();
+'foo'
+import g' \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/16_multiple_quotes.txt b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/16_multiple_quotes.txt
new file mode 100644
index 000000000..55a32a6f2
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/16_multiple_quotes.txt
@@ -0,0 +1,5 @@
+var dotenv = require('dotenv');
+dotenv.load();
+'foo'
+import g'
+"quote" and "unquote" \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/17_new_file_win.txt b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/17_new_file_win.txt
new file mode 100644
index 000000000..6dfa057f0
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/17_new_file_win.txt
@@ -0,0 +1 @@
+This is a new file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/18_sep_win.txt b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/18_sep_win.txt
new file mode 100644
index 000000000..b2f86910d
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/18_sep_win.txt
@@ -0,0 +1,2 @@
+This is a new file
+This is the last line
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/19_new_file_unix.text b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/19_new_file_unix.text
new file mode 100644
index 000000000..6dfa057f0
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/19_new_file_unix.text
@@ -0,0 +1 @@
+This is a new file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/20_sep_unix.text b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/20_sep_unix.text
new file mode 100644
index 000000000..b2f86910d
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/20_sep_unix.text
@@ -0,0 +1,2 @@
+This is a new file
+This is the last line
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/21_utf8_no_bom.txt b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/21_utf8_no_bom.txt
new file mode 100644
index 000000000..cd753877d
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/21_utf8_no_bom.txt
@@ -0,0 +1 @@
+This is a new utf-8 file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/22_utf8_no_bom_line_added.txt b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/22_utf8_no_bom_line_added.txt
new file mode 100644
index 000000000..3c3116a3e
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/22_utf8_no_bom_line_added.txt
@@ -0,0 +1,2 @@
+This is a new utf-8 file
+This is the last line
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/23_utf8_bom.txt b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/23_utf8_bom.txt
new file mode 100644
index 000000000..0873b7649
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/23_utf8_bom.txt
@@ -0,0 +1 @@
+This is a new utf-8 file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/24_utf8_bom_line_added.txt b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/24_utf8_bom_line_added.txt
new file mode 100644
index 000000000..484d75488
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/24_utf8_bom_line_added.txt
@@ -0,0 +1,2 @@
+This is a new utf-8 file
+This is the last line
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/25_utf16.txt16 b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/25_utf16.txt16
new file mode 100644
index 000000000..b9a0d1ae2
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/25_utf16.txt16
@@ -0,0 +1 @@
+This is a new utf-16 file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/26_utf16_line_added.txt16 b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/26_utf16_line_added.txt16
new file mode 100644
index 000000000..0a949dc4e
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/26_utf16_line_added.txt16
@@ -0,0 +1,2 @@
+This is a new utf-16 file
+This is the last line
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/27_utf32.txt32 b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/27_utf32.txt32
new file mode 100644
index 000000000..62e697f88
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/27_utf32.txt32
@@ -0,0 +1 @@
+This is a new utf-32 file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/28_utf32_line_added.txt32 b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/28_utf32_line_added.txt32
new file mode 100644
index 000000000..3d9af1c40
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/28_utf32_line_added.txt32
@@ -0,0 +1,2 @@
+This is a new utf-32 file
+This is the last line
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/29_no_linebreak.txt b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/29_no_linebreak.txt
new file mode 100644
index 000000000..dff2fa088
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/29_no_linebreak.txt
@@ -0,0 +1 @@
+c:\return\new \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/30_linebreaks_checksum_bad.txt b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/30_linebreaks_checksum_bad.txt
new file mode 100644
index 000000000..ffaa8767f
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/30_linebreaks_checksum_bad.txt
@@ -0,0 +1,3 @@
+c:\return\new
+c: eturn
+ew \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/31_relative_path.txt b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/31_relative_path.txt
new file mode 100644
index 000000000..01a263dbc
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/31_relative_path.txt
@@ -0,0 +1,6 @@
+New line at the beginning
+This is line 1
+This is line 2
+REF this is a line for backrefs REF
+This is line 4
+This is line 5
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/99_README.md b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/99_README.md
new file mode 100644
index 000000000..798b9c02e
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/expectations/99_README.md
@@ -0,0 +1,36 @@
+***WIN LINEINFILE Expectations***
+
+This folder contains expected files as the tests in this playbook executes on the
+files in 'files'.
+
+To get the checksum as would win_stat in the tests, go to this folder in powershell and
+execute
+
+```powershell
+Get-ChildItem | ForEach-Object {
+ $fp = [System.IO.File]::Open("$pwd/$($_.Name)", [System.IO.Filemode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::ReadWrite)
+ Write-Output $_.Name
+ try {
+ [System.BitConverter]::ToString($sp.ComputeHash($fp)).Replace("-", "").ToLower()
+ } finally {
+ $fp.Dispose()
+ }
+ Write-Output ""
+}
+```
+
+There is one exception right now: 30_linebreaks_checksum_bad.txt which requires mixed line endings that
+git cannot handle without turning the file binary. The file should read
+
+```
+c:\return\newCRLF
+c:CR
+eturnLF
+ew
+```
+where CR and LF denote carriage return (\r) and line feed (\n) respectively, to get the correct checksum.
+
+Also, the .gitattributes files is important as it assures that the EOL characters
+for the files are correct, regardless of environment. The files may be checked out on
+linux but the resulting files will be created using windows EOL, and the comparison must
+match. \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/test.txt b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/test.txt
new file mode 100644
index 000000000..8187db9f0
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/test.txt
@@ -0,0 +1,5 @@
+This is line 1
+This is line 2
+REF this is a line for backrefs REF
+This is line 4
+This is line 5
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/test_linebreak.txt b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/test_linebreak.txt
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/test_linebreak.txt
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/test_quoting.txt b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/test_quoting.txt
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/test_quoting.txt
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/testempty.txt b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/testempty.txt
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/testempty.txt
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/testnoeof.txt b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/testnoeof.txt
new file mode 100644
index 000000000..152780b9f
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/files/testnoeof.txt
@@ -0,0 +1,2 @@
+This is line 1
+This is line 2 \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/meta/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/meta/main.yml
new file mode 100644
index 000000000..9f37e96cd
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/meta/main.yml
@@ -0,0 +1,2 @@
+dependencies:
+- setup_remote_tmp_dir
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/tasks/main.yml
new file mode 100644
index 000000000..87748e595
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_lineinfile/tasks/main.yml
@@ -0,0 +1,803 @@
+# Test code for the win_lineinfile module, adapted from the standard lineinfile module tests
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+- name: deploy the test file for lineinfile
+ ansible.windows.win_copy: src=test.txt dest={{ remote_tmp_dir }}/test.txt
+ register: result
+
+- name: assert that the test file was deployed
+ assert:
+ that:
+ - "result.changed == true"
+
+- name: stat the test file
+ # Note: The test.txt is copied from a Linux host, therefore it will retain
+ # unix line ending when stat'd here. This affects checksum, meaning that
+ # when this repo is checked out to Windows, checksum does not match checked-
+ # out file checksum unless line-endings are altered.
+ ansible.windows.win_stat: path={{ remote_tmp_dir }}/test.txt
+ register: result
+
+- name: check win_stat file result
+ assert:
+ that:
+ - "result.stat.exists"
+ - "not result.stat.isdir"
+ - "result.stat.checksum == '5feac65e442c91f557fc90069ce6efc4d346ab51'"
+ - "result is not failed"
+ - "result is not changed"
+
+
+- name: insert a line at the beginning of the file, and back it up
+ # 01
+ win_lineinfile: dest={{ remote_tmp_dir }}/test.txt state=present line="New line at the beginning" insertbefore="BOF" backup=yes
+ register: result
+
+- name: check backup_file
+ ansible.windows.win_stat:
+ path: '{{ result.backup_file }}'
+ register: backup_file
+
+- name: assert that the line was inserted at the head of the file
+ assert:
+ that:
+ - result.changed == true
+ - result.msg == 'line added'
+ - backup_file.stat.exists == true
+
+- name: stat the backup file
+ ansible.windows.win_stat: path={{result.backup}}
+ register: result
+
+- name: assert the backup file matches the previous hash
+ assert:
+ that:
+ - "result.stat.checksum == '5feac65e442c91f557fc90069ce6efc4d346ab51'"
+
+- name: stat the test after the insert at the head
+ ansible.windows.win_stat: path={{ remote_tmp_dir }}/test.txt
+ register: result
+
+- name: assert test hash is what we expect for the file with the insert at the head
+ assert:
+ that:
+ - result.stat.checksum == 'c61233b0ee2038aab41b5f30683c57b2a013b376'
+
+- name: insert a line at the end of the file
+ # 02
+ win_lineinfile: dest={{ remote_tmp_dir }}/test.txt state=present line="New line at the end" insertafter="EOF"
+ register: result
+
+- name: assert that the line was inserted at the end of the file
+ assert:
+ that:
+ - "result.changed == true"
+ - "result.msg == 'line added'"
+
+- name: stat the test after the insert at the end
+ ansible.windows.win_stat: path={{ remote_tmp_dir }}/test.txt
+ register: result
+
+- name: assert test checksum matches after the insert at the end
+ assert:
+ that:
+ - result.stat.checksum == 'a91260ad67b00609cc0737ff70ac5170c6a519a8'
+
+- name: insert a line after the first line
+ # 03
+ win_lineinfile: dest={{ remote_tmp_dir }}/test.txt state=present line="New line after line 1" insertafter="^This is line 1$"
+ register: result
+
+- name: assert that the line was inserted after the first line
+ assert:
+ that:
+ - "result.changed == true"
+ - "result.msg == 'line added'"
+
+- name: stat the test after insert after the first line
+ ansible.windows.win_stat: path={{ remote_tmp_dir }}/test.txt
+ register: result
+
+- name: assert test checksum matches after the insert after the first line
+ assert:
+ that:
+ - result.stat.checksum == '6ffbabdaa21ecb3593d32144de535598cfd7c6ea'
+
+- name: insert a line before the last line
+ # 04
+ win_lineinfile: dest={{ remote_tmp_dir }}/test.txt state=present line="New line before line 5" insertbefore="^This is line 5$"
+ register: result
+
+- name: assert that the line was inserted before the last line
+ assert:
+ that:
+ - "result.changed == true"
+ - "result.msg == 'line added'"
+
+- name: stat the test after the insert before the last line
+ ansible.windows.win_stat: path={{ remote_tmp_dir }}/test.txt
+ register: result
+
+- name: assert test checksum matches after the insert before the last line
+ assert:
+ that:
+ - result.stat.checksum == '49d988ad97fb4cce3ad795c8459f1cde231a891b'
+
+- name: replace a line with backrefs
+ # 05
+ win_lineinfile: dest={{ remote_tmp_dir }}/test.txt state=present line="This is line 3" backrefs=yes regexp="^(REF).*$"
+ register: result
+
+- name: assert that the line with backrefs was changed
+ assert:
+ that:
+ - "result.changed == true"
+ - "result.msg == 'line replaced'"
+
+
+- name: stat the test after the backref line was replaced
+ ansible.windows.win_stat: path={{ remote_tmp_dir }}/test.txt
+ register: result
+
+- name: assert test checksum matches after backref line was replaced
+ assert:
+ that:
+ - result.stat.checksum == '6f9c2128f4c886f3c40c1f1cf50241d74f160437'
+
+- name: remove the middle line
+ # 06
+ win_lineinfile: dest={{ remote_tmp_dir }}/test.txt state=absent regexp="^This is line 3$"
+ register: result
+
+- name: assert that the line was removed
+ assert:
+ that:
+ - "result.changed == true"
+ - "result.msg == '1 line(s) removed'"
+
+- name: stat the test after the middle line was removed
+ ansible.windows.win_stat: path={{ remote_tmp_dir }}/test.txt
+ register: result
+
+- name: assert test checksum matches after the middle line was removed
+ assert:
+ that:
+ - result.stat.checksum == '4b7910c84bd1177b9013f277c85d5be55f384a36'
+
+- name: run a validation script that succeeds
+ # 07
+ win_lineinfile: dest={{ remote_tmp_dir }}/test.txt state=absent regexp="^This is line 5$" validate="sort.exe %s"
+ register: result
+
+- name: assert that the file validated after removing a line
+ assert:
+ that:
+ - "result.changed == true"
+ - "result.msg == '1 line(s) removed'"
+
+- name: stat the test after the validation succeeded
+ ansible.windows.win_stat: path={{ remote_tmp_dir }}/test.txt
+ register: result
+
+- name: assert test checksum matches after the validation succeeded
+ assert:
+ that:
+ - result.stat.checksum == '938afecdcde51fda42ddbea6f2e92876e710f289'
+
+- name: run a validation script that fails
+ # 08
+ win_lineinfile: dest={{ remote_tmp_dir }}/test.txt state=absent regexp="^This is line 1$" validate="sort.exe %s.foo"
+ register: result
+ ignore_errors: yes
+
+- name: assert that the validate failed
+ assert:
+ that:
+ - "result.failed == true"
+
+- name: stat the test after the validation failed
+ ansible.windows.win_stat: path={{ remote_tmp_dir }}/test.txt
+ register: result
+
+- name: assert test checksum matches the previous after the validation failed
+ assert:
+ that:
+ - result.stat.checksum == '938afecdcde51fda42ddbea6f2e92876e710f289'
+
+- name: use create=yes
+ # 09
+ win_lineinfile: dest={{ remote_tmp_dir }}/new_test.txt create=yes insertbefore=BOF state=present line="This is a new file"
+ register: result
+
+- name: assert that the new file was created
+ assert:
+ that:
+ - "result.changed == true"
+ - "result.msg == 'line added'"
+
+- name: validate that the newly created file exists
+ ansible.windows.win_stat: path={{ remote_tmp_dir }}/new_test.txt
+ register: result
+ ignore_errors: yes
+
+- name: assert the newly created test checksum matches
+ assert:
+ that:
+ - result.stat.checksum == '84faac1183841c57434693752fc3debc91b9195d'
+
+# Test EOF in cases where file has no newline at EOF
+- name: testnoeof deploy the file for lineinfile
+ ansible.windows.win_copy: src=testnoeof.txt dest={{ remote_tmp_dir }}/testnoeof.txt
+ register: result
+
+- name: testnoeof insert a line at the end of the file
+ # 10
+ win_lineinfile: dest={{ remote_tmp_dir }}/testnoeof.txt state=present line="New line at the end" insertafter="EOF"
+ register: result
+
+- name: testempty assert that the line was inserted at the end of the file
+ assert:
+ that:
+ - "result.changed == true"
+ - "result.msg == 'line added'"
+
+- name: testnoeof stat the no newline EOF test after the insert at the end
+ ansible.windows.win_stat: path={{ remote_tmp_dir }}/testnoeof.txt
+ register: result
+
+- name: testnoeof assert test checksum matches after the insert at the end
+ assert:
+ that:
+ - result.stat.checksum == '229852b09f7e9921fbcbb0ee0166ba78f7f7f261'
+
+- name: add multiple lines at the end of the file
+ # 11
+ win_lineinfile: dest={{ remote_tmp_dir }}/test.txt state=present line="This is a line\r\nwith newline character" insertafter="EOF"
+ register: result
+
+- name: assert that the multiple lines was inserted
+ assert:
+ that:
+ - "result.changed == true"
+ - "result.msg == 'line added'"
+
+- name: stat file after adding multiple lines
+ ansible.windows.win_stat: path={{ remote_tmp_dir }}/test.txt
+ register: result
+
+- name: assert test checksum matches after inserting multiple lines
+ assert:
+ that:
+ - result.stat.checksum == 'd10d70cb77a16fb54f143bccbf711f3177acd310'
+
+
+
+# Test EOF with empty file to make sure no unnecessary newline is added
+- name: testempty deploy the testempty file for lineinfile
+ ansible.windows.win_copy: src=testempty.txt dest={{ remote_tmp_dir }}/testempty.txt
+ register: result
+
+- name: testempty insert a line at the end of the file
+ # 12
+ win_lineinfile: dest={{ remote_tmp_dir }}/testempty.txt state=present line="New line at the end" insertafter="EOF"
+ register: result
+
+- name: testempty assert that the line was inserted at the end of the file
+ assert:
+ that:
+ - "result.changed == true"
+ - "result.msg == 'line added'"
+
+- name: testempty stat the test after the insert at the end
+ ansible.windows.win_stat: path={{ remote_tmp_dir }}/testempty.txt
+ register: result
+
+- name: testempty assert test checksum matches after the insert at the end
+ assert:
+ that:
+ - result.stat.checksum == 'd3d34f11edda51be7ca5dcb0757cf3e1257c0bfe'
+
+- name: replace a line with backrefs included in the line
+ # 13
+ win_lineinfile: dest={{ remote_tmp_dir }}/test.txt state=present line="New $1 created with the backref" backrefs=yes regexp="^This is (line 4)$"
+ register: result
+
+- name: assert that the line with backrefs was changed
+ assert:
+ that:
+ - "result.changed == true"
+ - "result.msg == 'line replaced'"
+
+- name: stat the test after the backref line was replaced
+ ansible.windows.win_stat: path={{ remote_tmp_dir }}/test.txt
+ register: result
+
+- name: assert test checksum matches after backref line was replaced
+ assert:
+ that:
+ - result.stat.checksum == '9c1a1451b50665e59be666c5d8c08fb99603d4f1'
+
+###################################################################
+# issue 8535
+
+- name: create a new file for testing quoting issues
+ # 14
+ ansible.windows.win_copy: src=test_quoting.txt dest={{ remote_tmp_dir }}/test_quoting.txt
+ register: result
+
+- name: assert the new file was created
+ assert:
+ that:
+ - result.changed
+
+- name: use with_items to add code-like strings to the quoting txt file
+ win_lineinfile: >
+ dest={{ remote_tmp_dir }}/test_quoting.txt
+ line="{{ item }}"
+ insertbefore="BOF"
+ with_items:
+ - "'foo'"
+ - "dotenv.load();"
+ - "var dotenv = require('dotenv');"
+ register: result
+
+- name: assert the quote test file was modified correctly
+ assert:
+ that:
+ - result.results|length == 3
+ - result.results[0].changed
+ - result.results[0].item == "'foo'"
+ - result.results[1].changed
+ - result.results[1].item == "dotenv.load();"
+ - result.results[2].changed
+ - result.results[2].item == "var dotenv = require('dotenv');"
+
+- name: stat the quote test file
+ ansible.windows.win_stat: path={{ remote_tmp_dir }}/test_quoting.txt
+ register: result
+
+- name: assert test checksum matches for quote test file
+ assert:
+ that:
+ - result.stat.checksum == 'f3bccdbdfa1d7176c497ef87d04957af40ab48d2'
+
+- name: append a line into the quoted file with a single quote
+ # 15
+ win_lineinfile: dest={{ remote_tmp_dir }}/test_quoting.txt line="import g'"
+ register: result
+
+- name: assert that the quoted file was changed
+ assert:
+ that:
+ - result.changed
+
+- name: stat the quote test file
+ ansible.windows.win_stat: path={{ remote_tmp_dir }}/test_quoting.txt
+ register: result
+
+- name: assert test checksum matches adding line with single quote
+ assert:
+ that:
+ - result.stat.checksum == 'dabf4cbe471e1797d8dcfc773b6b638c524d5237'
+
+- name: insert a line into the quoted file with many double quotation strings
+ # 16
+ win_lineinfile: dest={{ remote_tmp_dir }}/test_quoting.txt line='"quote" and "unquote"'
+ register: result
+
+- name: assert that the quoted file was changed
+ assert:
+ that:
+ - result.changed
+
+- name: stat the quote test file
+ ansible.windows.win_stat: path={{ remote_tmp_dir }}/test_quoting.txt
+ register: result
+
+- name: assert test checksum matches quoted line added
+ assert:
+ that:
+ - result.stat.checksum == '9dc1fc1ff19942e2936564102ad37134fa83b91d'
+
+
+# Windows vs. Unix line separator test cases
+- name: Create windows test file with initial line
+ # 17
+ win_lineinfile: dest={{ remote_tmp_dir }}/test_windows_sep.txt create=yes insertbefore=BOF state=present line="This is a new file"
+ register: result
+
+- name: assert that the new file was created
+ assert:
+ that:
+ - "result.changed == true"
+ - "result.msg == 'line added'"
+
+- name: validate that the newly created file exists
+ ansible.windows.win_stat: path={{ remote_tmp_dir }}/test_windows_sep.txt
+ register: result
+
+- name: assert the newly created file checksum matches
+ assert:
+ that:
+ - result.stat.checksum == '84faac1183841c57434693752fc3debc91b9195d'
+
+- name: Test appending to the file using the default (windows) line separator
+ # 18
+ win_lineinfile: dest={{ remote_tmp_dir }}/test_windows_sep.txt insertbefore=EOF state=present line="This is the last line"
+ register: result
+
+- name: assert that the new line was added
+ assert:
+ that:
+ - "result.changed == true"
+ - "result.msg == 'line added'"
+
+- name: stat the file
+ ansible.windows.win_stat: path={{ remote_tmp_dir }}/test_windows_sep.txt
+ register: result
+
+- name: assert the file checksum matches expected checksum
+ assert:
+ that:
+ - result.stat.checksum == '6c6f51f98eb499852fbb7ef3b212c26752c25c31'
+
+
+- name: Create unix test file with initial line
+ # 19
+ win_lineinfile: dest={{ remote_tmp_dir }}/test_unix_sep.txt create=yes insertbefore=BOF state=present line="This is a new file"
+ register: result
+
+- name: assert that the new file was created
+ assert:
+ that:
+ - "result.changed == true"
+ - "result.msg == 'line added'"
+
+- name: validate that the newly created file exists
+ ansible.windows.win_stat: path={{ remote_tmp_dir }}/test_unix_sep.txt
+ register: result
+
+- name: assert the newly created file checksum matches
+ assert:
+ that:
+ - result.stat.checksum == '84faac1183841c57434693752fc3debc91b9195d'
+
+- name: Test appending to the file using unix line separator
+ # 20
+ win_lineinfile: dest={{ remote_tmp_dir }}/test_unix_sep.txt insertbefore=EOF state=present line="This is the last line" newline="unix"
+ register: result
+
+- name: assert that the new line was added
+ assert:
+ that:
+ - "result.changed == true"
+ - "result.msg == 'line added'"
+
+- name: stat the file
+ ansible.windows.win_stat: path={{ remote_tmp_dir }}/test_unix_sep.txt
+ register: result
+
+- name: assert the file checksum matches expected checksum
+ assert:
+ that:
+ - result.stat.checksum == '4aa2ad771bb1453406760eadee8234265d599dcf'
+
+
+# Encoding management test cases
+
+# Default (auto) encoding should use utf-8 with no BOM
+- name: Test create file without explicit encoding results in utf-8 without BOM
+ # 21
+ win_lineinfile: dest={{ remote_tmp_dir }}/test_auto_utf8.txt create=yes insertbefore=BOF state=present line="This is a new utf-8 file"
+ register: result
+
+- name: assert that the new file was created
+ assert:
+ that:
+ - "result.changed == true"
+ - "result.msg == 'line added'"
+ - "result.encoding == 'utf-8'"
+
+- name: validate that the newly created file exists
+ ansible.windows.win_stat: path={{ remote_tmp_dir }}/test_auto_utf8.txt
+ register: result
+
+- name: assert the newly created file checksum matches
+ assert:
+ that:
+ - result.stat.checksum == 'b69fcbacca8291a4668f57fba91d7c022f1c3dc7'
+
+- name: Test appending to the utf-8 without BOM file - should autodetect UTF-8 no BOM
+ # 22
+ win_lineinfile: dest={{ remote_tmp_dir }}/test_auto_utf8.txt insertbefore=EOF state=present line="This is the last line"
+ register: result
+
+- name: assert that the new line was added and encoding did not change
+ assert:
+ that:
+ - "result.changed == true"
+ - "result.msg == 'line added'"
+ - "result.encoding == 'utf-8'"
+
+- name: stat the file
+ ansible.windows.win_stat: path={{ remote_tmp_dir }}/test_auto_utf8.txt
+ register: result
+
+- name: assert the file checksum matches
+ assert:
+ that:
+ - result.stat.checksum == 'aeb246a40f614889534f4983f47c5567625ade53'
+
+
+# UTF-8 explicit (with BOM)
+- name: Test create file with explicit utf-8 encoding results in utf-8 with a BOM
+ # 23
+ win_lineinfile: dest={{ remote_tmp_dir }}/test_utf8.txt create=yes encoding="utf-8" insertbefore=BOF state=present line="This is a new utf-8 file"
+ register: result
+
+- name: assert that the new file was created
+ assert:
+ that:
+ - "result.changed == true"
+ - "result.msg == 'line added'"
+ - "result.encoding == 'utf-8'"
+
+- name: validate that the newly created file exists
+ ansible.windows.win_stat: path={{ remote_tmp_dir }}/test_utf8.txt
+ register: result
+
+- name: assert the newly created file checksum matches
+ assert:
+ that:
+ - result.stat.checksum == 'd45344b2b3bf1cf90eae851b40612f5f37a88bbb'
+
+- name: Test appending to the utf-8 with BOM file - should autodetect utf-8 with BOM encoding
+ # 24
+ win_lineinfile: dest={{ remote_tmp_dir }}/test_utf8.txt insertbefore=EOF state=present line="This is the last line"
+ register: result
+
+- name: assert that the new line was added and encoding did not change
+ assert:
+ that:
+ - "result.changed == true"
+ - "result.msg == 'line added'"
+ - "result.encoding == 'utf-8'"
+
+- name: stat the file
+ ansible.windows.win_stat: path={{ remote_tmp_dir }}/test_utf8.txt
+ register: result
+
+- name: assert the file checksum matches
+ assert:
+ that:
+ - result.stat.checksum == '64c62066d06ea6c807a8fe98bc40c4903cf4c119'
+
+
+# UTF-16 explicit
+- name: Test create file with explicit utf-16 encoding
+ # 25
+ win_lineinfile: dest={{ remote_tmp_dir }}/test_utf16.txt create=yes encoding="utf-16" insertbefore=BOF state=present line="This is a new utf-16 file"
+ register: result
+
+- name: assert that the new file was created
+ assert:
+ that:
+ - "result.changed == true"
+ - "result.msg == 'line added'"
+ - "result.encoding == 'utf-16'"
+
+- name: validate that the newly created file exists
+ ansible.windows.win_stat: path={{ remote_tmp_dir }}/test_utf16.txt
+ register: result
+
+- name: assert the newly created file checksum matches
+ assert:
+ that:
+ - result.stat.checksum == '785b0693cec13b60e2c232782adeda2f8a967434'
+
+- name: Test appending to the utf-16 file - should autodetect utf-16 encoding
+ # 26
+ win_lineinfile: dest={{ remote_tmp_dir }}/test_utf16.txt insertbefore=EOF state=present line="This is the last line"
+ register: result
+
+- name: assert that the new line was added and encoding did not change
+ assert:
+ that:
+ - "result.changed == true"
+ - "result.msg == 'line added'"
+ - "result.encoding == 'utf-16'"
+
+- name: stat the file
+ ansible.windows.win_stat: path={{ remote_tmp_dir }}/test_utf16.txt
+ register: result
+
+- name: assert the file checksum matches
+ assert:
+ that:
+ - result.stat.checksum == '7f790f323e496b7138883a3634514cc2a3426919'
+
+# UTF-32 explicit
+- name: Test create file with explicit utf-32 encoding
+ # 27
+ win_lineinfile: dest={{ remote_tmp_dir }}/test_utf32.txt create=yes encoding="utf-32" insertbefore=BOF state=present line="This is a new utf-32 file"
+ register: result
+
+- name: assert that the new file was created
+ assert:
+ that:
+ - "result.changed == true"
+ - "result.msg == 'line added'"
+ - "result.encoding == 'utf-32'"
+
+- name: validate that the newly created file exists
+ ansible.windows.win_stat: path={{ remote_tmp_dir }}/test_utf32.txt
+ register: result
+
+- name: assert the newly created file checksum matches
+ assert:
+ that:
+ - result.stat.checksum == '7a6e3f3604c0def431aaa813173a4ddaa10fd1fb'
+
+- name: Test appending to the utf-32 file - should autodetect utf-32 encoding
+ # 28
+ win_lineinfile: dest={{ remote_tmp_dir }}/test_utf32.txt insertbefore=EOF state=present line="This is the last line"
+ register: result
+
+- name: assert that the new line was added and encoding did not change
+ assert:
+ that:
+ - "result.changed == true"
+ - "result.msg == 'line added'"
+ - "result.encoding == 'utf-32'"
+
+- name: stat the file
+ ansible.windows.win_stat: path={{ remote_tmp_dir }}/test_utf32.txt
+ register: result
+
+- name: assert the file checksum matches
+ assert:
+ that:
+ - result.stat.checksum == 'd13e135c7d466cc2f985d72f12ffaa73567772e6'
+
+#########################################################################
+# issue #33858
+# \r\n causes line break instead of printing literally which breaks paths.
+
+- name: create testing file
+ ansible.windows.win_copy:
+ src: test_linebreak.txt
+ dest: "{{ remote_tmp_dir }}/test_linebreak.txt"
+
+- name: stat the test file
+ ansible.windows.win_stat:
+ path: "{{ remote_tmp_dir }}/test_linebreak.txt"
+ register: result
+
+- name: check win_stat file result
+ assert:
+ that:
+ - result.stat.exists
+ - not result.stat.isdir
+ - result.stat.checksum == 'da39a3ee5e6b4b0d3255bfef95601890afd80709'
+ - result is not failed
+ - result is not changed
+
+- name: insert path c:\return\new to test file
+ # 29
+ win_lineinfile:
+ dest: "{{ remote_tmp_dir }}/test_linebreak.txt"
+ line: c:\return\new
+ register: result_literal
+
+- name: insert path "c:\return\new" to test file, will cause line breaks
+ # 30
+ win_lineinfile:
+ dest: "{{ remote_tmp_dir }}/test_linebreak.txt"
+ line: "c:\return\new"
+ register: result_expand
+
+- name: assert that the lines were inserted
+ assert:
+ that:
+ - result_literal.changed == true
+ - result_literal.msg == 'line added'
+ - result_expand.changed == true
+ - result_expand.msg == 'line added'
+
+- name: stat the test file
+ ansible.windows.win_stat:
+ path: "{{ remote_tmp_dir }}/test_linebreak.txt"
+ register: result
+
+- name: assert that one line is literal and the other has breaks
+ assert:
+ that:
+ - result.stat.checksum == 'd2dfd11bc70526ff13a91153c76a7ae5595a845b'
+
+- name: Get current working directory
+ win_shell: $pwd.Path
+ register: pwd
+
+- name: create a relative tmp dir
+ ansible.windows.win_tempfile:
+ path: "{{ pwd.stdout | trim | win_dirname }}"
+ state: directory
+ register: relative_tmp_dir
+
+- name: Check that relative paths work
+ block:
+ - name: deploy the test file for lineinfile
+ ansible.windows.win_copy: src=test.txt dest={{ relative_tmp_dir.path }}/test.txt
+ register: result
+
+ - name: assert that the test file was deployed
+ assert:
+ that:
+ - "result.changed == true"
+
+ - name: stat the test file
+ ansible.windows.win_stat: path={{ relative_tmp_dir.path }}/test.txt
+ register: result
+
+ - name: check win_stat file result
+ assert:
+ that:
+ - "result.stat.exists"
+ - "not result.stat.isdir"
+ - "result.stat.checksum == '5feac65e442c91f557fc90069ce6efc4d346ab51'"
+ - "result is not failed"
+ - "result is not changed"
+
+ - name: insert a line at the beginning of the file, and back it up
+ # 31
+ win_lineinfile: dest=../{{ relative_tmp_dir.path | win_basename }}/test.txt state=present line="New line at the beginning" insertbefore="BOF" backup=yes
+ register: result
+
+ - name: check backup_file
+ ansible.windows.win_stat:
+ path: '{{ result.backup_file }}'
+ register: backup_file
+
+ - name: assert that the line was inserted at the head of the file
+ assert:
+ that:
+ - result.changed == true
+ - result.msg == 'line added'
+ - backup_file.stat.exists == true
+
+ - name: stat the backup file
+ ansible.windows.win_stat: path={{result.backup}}
+ register: result
+
+ - name: assert the backup file matches the previous hash
+ assert:
+ that:
+ - "result.stat.checksum == '5feac65e442c91f557fc90069ce6efc4d346ab51'"
+
+ - name: stat the test after the insert at the head
+ ansible.windows.win_stat: path={{ relative_tmp_dir.path }}/test.txt
+ register: result
+
+ - name: assert test hash is what we expect for the file with the insert at the head
+ assert:
+ that:
+ - result.stat.checksum == 'c61233b0ee2038aab41b5f30683c57b2a013b376'
+
+ always:
+ - ansible.windows.win_file:
+ path: "{{ relative_tmp_dir.path }}"
+ state: absent
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_listen_ports_facts/aliases b/ansible_collections/community/windows/tests/integration/targets/win_listen_ports_facts/aliases
new file mode 100644
index 000000000..4f4664b68
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_listen_ports_facts/aliases
@@ -0,0 +1 @@
+shippable/windows/group5
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_listen_ports_facts/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_listen_ports_facts/tasks/main.yml
new file mode 100644
index 000000000..77649d8f1
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_listen_ports_facts/tasks/main.yml
@@ -0,0 +1,45 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2022, DataDope (@datadope-io)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: Gather facts with invalid tcp_filter state and null date format
+ win_listen_ports_facts:
+ tcp_filter:
+ - Error
+ date_format: null
+ register: invalid_state_date_run
+ ignore_errors: True
+
+- name: Gather facts with only some invalid tcp_filter states and null date format
+ win_listen_ports_facts:
+ tcp_filter:
+ - Listen
+ - Closed
+ - Error
+ date_format: null
+ register: partial_invalid_state_date_run
+ ignore_errors: True
+
+- name: Gather facts with multiple filters and custom date format
+ win_listen_ports_facts:
+ tcp_filter:
+ - Listen
+ - Closed
+ date_format: yyyy
+ register: custom_state_date_run
+ ignore_errors: True
+
+- name: Gather facts with default filters and date format
+ win_listen_ports_facts:
+ register: default_run
+ ignore_errors: True
+
+- assert:
+ that:
+ - invalid_state_date_run.failed is defined and invalid_state_date_run.failed
+ - partial_invalid_state_date_run.failed is defined and partial_invalid_state_date_run.failed
+ - custom_state_date_run.failed is not defined or not custom_state_date_run.failed
+ - default_run.failed is not defined or not default_run.failed
+ - tcp_listen is defined
+ - udp_listen is defined
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_mapped_drive/aliases b/ansible_collections/community/windows/tests/integration/targets/win_mapped_drive/aliases
new file mode 100644
index 000000000..4f4664b68
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_mapped_drive/aliases
@@ -0,0 +1 @@
+shippable/windows/group5
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_mapped_drive/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_mapped_drive/defaults/main.yml
new file mode 100644
index 000000000..6e8ed002e
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_mapped_drive/defaults/main.yml
@@ -0,0 +1,9 @@
+test_win_mapped_drive_letter: M
+test_win_mapped_drive_path: share1
+test_win_mapped_drive_path2: share2
+
+test_win_mapped_drive_local_path: C:\ansible\win_mapped_drive\share1
+test_win_mapped_drive_local_path2: C:\ansible\win_mapped_drive\share2
+
+test_win_mapped_drive_temp_user: TestMappedUser
+test_win_mapped_drive_temp_password: aZ293jgkdslgj4
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_mapped_drive/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_mapped_drive/tasks/main.yml
new file mode 100644
index 000000000..19d5acb2c
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_mapped_drive/tasks/main.yml
@@ -0,0 +1,99 @@
+---
+# test setup
+- name: gather facts required by the tests
+ ansible.windows.setup:
+ gather_subset: platform
+
+- name: ensure mapped drive is deleted before test
+ win_mapped_drive:
+ letter: '{{test_win_mapped_drive_letter}}'
+ state: absent
+
+- name: ensure temp mapped drive user exist
+ ansible.windows.win_user:
+ name: '{{test_win_mapped_drive_temp_user}}'
+ password: '{{test_win_mapped_drive_temp_password}}'
+ state: present
+ groups:
+ - Administrators
+
+- name: ensure temp folders exist
+ ansible.windows.win_file:
+ path: '{{item}}'
+ state: directory
+ with_items:
+ - '{{test_win_mapped_drive_local_path}}'
+ - '{{test_win_mapped_drive_local_path2}}'
+
+# can't use win_share as it doesnt't support Server 2008 and 2008 R2
+- name: ensure shares exist
+ ansible.windows.win_shell: $share = Get-WmiObject -Class Win32_Share | Where-Object { $_.Name -eq '{{item.name}}' }; if (-not $share) { $share = [wmiClass]'Win32_Share'; $share.Create('{{item.path}}', '{{item.name}}', 0) }
+ with_items:
+ - { name: '{{test_win_mapped_drive_path}}', path: '{{test_win_mapped_drive_local_path}}' }
+ - { name: '{{test_win_mapped_drive_path2}}', path: '{{test_win_mapped_drive_local_path2}}' }
+
+# This ensures we test out the split token/become behaviour
+- name: ensure builtin Administrator has a split token
+ ansible.windows.win_regedit:
+ path: HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System
+ name: FilterAdministratorToken
+ data: 1
+ type: dword
+ register: admin_uac
+
+- name: reboot to apply Admin approval mode setting
+ ansible.windows.win_reboot:
+ when: admin_uac is changed
+
+- block:
+ # tests
+ - include_tasks: tests.yml
+
+ # test cleanup
+ always:
+ - name: remove stored credential
+ win_credential:
+ name: '{{ ansible_hostname }}'
+ type: domain_password
+ state: absent
+ vars:
+ ansible_become: yes
+ ansible_become_method: runas
+ ansible_become_user: '{{ ansible_user }}'
+ ansible_become_pass: '{{ ansible_password }}'
+
+ - name: ensure mapped drive is deleted at the end of the test
+ win_mapped_drive:
+ letter: '{{test_win_mapped_drive_letter}}'
+ state: absent
+
+ - name: ensure shares are removed
+ ansible.windows.win_shell: $share = Get-WmiObject -Class Win32_Share | Where-Object { $_.Name -eq '{{item}}' }; if ($share) { $share.Delete() }
+ with_items:
+ - '{{test_win_mapped_drive_path}}'
+ - '{{test_win_mapped_drive_path2}}'
+
+ - name: ensure temp folders are deleted
+ ansible.windows.win_file:
+ path: '{{item}}'
+ state: absent
+ with_items:
+ - '{{test_win_mapped_drive_local_path}}'
+ - '{{test_win_mapped_drive_local_path2}}'
+
+ - name: ensure temp mapped driver user is deleted
+ ansible.windows.win_user:
+ name: '{{test_win_mapped_drive_temp_user}}'
+ state: absent
+
+ - name: disable Admin approval mode if changed in test
+ ansible.windows.win_regedit:
+ path: HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System
+ name: FilterAdministratorToken
+ data: 0
+ type: dword
+ when: admin_uac is changed
+
+ - name: reboot to apply Admin approval mode setting
+ ansible.windows.win_reboot:
+ when: admin_uac is changed
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_mapped_drive/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_mapped_drive/tasks/tests.yml
new file mode 100644
index 000000000..2529b8ba1
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_mapped_drive/tasks/tests.yml
@@ -0,0 +1,344 @@
+---
+- name: fail with invalid path
+ win_mapped_drive:
+ letter: invalid
+ state: absent
+ register: fail_invalid_letter
+ failed_when: "fail_invalid_letter.msg != 'letter must be a single letter from A-Z, was: invalid'"
+
+- name: fail without specify path when creating drive
+ win_mapped_drive:
+ letter: '{{test_win_mapped_drive_letter}}'
+ state: present
+ register: fail_path_missing
+ failed_when: "fail_path_missing.msg != 'state is present but all of the following are missing: path'"
+
+- name: fail when specifying letter with existing physical path
+ win_mapped_drive:
+ letter: c
+ path: \\{{ansible_hostname}}\{{test_win_mapped_drive_path}}
+ state: present
+ register: fail_local_letter
+ failed_when: fail_local_letter.msg != 'failed to create mapped drive c, this letter is in use and is pointing to a non UNC path'
+
+- name: create mapped drive check
+ win_mapped_drive:
+ letter: '{{test_win_mapped_drive_letter}}'
+ path: \\{{ansible_hostname}}\{{test_win_mapped_drive_path}}
+ state: present
+ register: create_drive_check
+ check_mode: yes
+
+- name: get actual of create mapped drive check
+ ansible.windows.win_command: 'net use {{test_win_mapped_drive_letter}}:' # Get-PSDrive/Get-WmiObject/Get-CimInstance doesn't work over WinRM
+ register: create_drive_actual_check
+ failed_when: False
+
+- name: assert create mapped drive check
+ assert:
+ that:
+ - create_drive_check is changed
+ - create_drive_actual_check.rc == 2 # should fail with this error code when it isn't found
+
+- name: create mapped drive
+ win_mapped_drive:
+ letter: '{{test_win_mapped_drive_letter}}'
+ path: \\{{ansible_hostname}}\{{test_win_mapped_drive_path}}
+ state: present
+ register: create_drive
+
+- name: get actual of create mapped drive
+ ansible.windows.win_command: 'net use {{test_win_mapped_drive_letter}}:'
+ register: create_drive_actual
+
+- name: assert create mapped drive
+ assert:
+ that:
+ - create_drive is changed
+ - create_drive_actual.rc == 0
+ - create_drive_actual.stdout_lines[1] == "Remote name \\\\{{ansible_hostname}}\\{{test_win_mapped_drive_path}}"
+
+- name: create mapped drive again
+ win_mapped_drive:
+ letter: '{{test_win_mapped_drive_letter}}'
+ path: \\{{ansible_hostname}}\{{test_win_mapped_drive_path}}
+ state: present
+ register: create_drive_again
+
+- name: assert create mapped drive again
+ assert:
+ that:
+ - create_drive_again is not changed
+
+- name: change mapped drive target check
+ win_mapped_drive:
+ letter: '{{test_win_mapped_drive_letter}}'
+ path: \\{{ansible_hostname}}\{{test_win_mapped_drive_path2}}
+ state: present
+ register: change_drive_target_check
+ check_mode: yes
+
+- name: get actual of change mapped drive target check
+ ansible.windows.win_command: 'net use {{test_win_mapped_drive_letter}}:'
+ register: change_drive_target_actual_check
+
+- name: assert change mapped drive target check
+ assert:
+ that:
+ - change_drive_target_check is changed
+ - change_drive_target_actual_check.rc == 0
+ - change_drive_target_actual_check.stdout_lines[1] == "Remote name \\\\{{ansible_hostname}}\\{{test_win_mapped_drive_path}}"
+
+- name: change mapped drive target
+ win_mapped_drive:
+ letter: '{{test_win_mapped_drive_letter}}'
+ path: \\{{ansible_hostname}}\{{test_win_mapped_drive_path2}}
+ state: present
+ register: change_drive_target
+
+- name: get actual of change mapped drive target
+ ansible.windows.win_command: 'net use {{test_win_mapped_drive_letter}}:'
+ register: change_drive_target_actual
+
+- name: assert change mapped drive target
+ assert:
+ that:
+ - change_drive_target is changed
+ - change_drive_target_actual.rc == 0
+ - change_drive_target_actual.stdout_lines[1] == "Remote name \\\\{{ansible_hostname}}\\{{test_win_mapped_drive_path2}}"
+
+- name: fail to delete mapped drive if target doesn't match
+ win_mapped_drive:
+ letter: '{{test_win_mapped_drive_letter}}'
+ path: \\{{ansible_hostname}}\{{test_win_mapped_drive_path}}
+ state: absent
+ register: fail_delete_incorrect_target
+ failed_when: fail_delete_incorrect_target.msg != 'did not delete mapped drive ' + test_win_mapped_drive_letter + ', the target path is pointing to a different location at \\\\' + ansible_hostname + '\\' + test_win_mapped_drive_path2
+
+- name: delete mapped drive check
+ win_mapped_drive:
+ letter: '{{test_win_mapped_drive_letter}}'
+ path: \\{{ansible_hostname}}\{{test_win_mapped_drive_path2}}
+ state: absent
+ register: delete_drive_check
+ check_mode: yes
+
+- name: get actual of delete mapped drive check
+ ansible.windows.win_command: 'net use {{test_win_mapped_drive_letter}}:'
+ register: delete_drive_actual_check
+
+- name: assert delete mapped drive check
+ assert:
+ that:
+ - delete_drive_check is changed
+ - delete_drive_actual_check.rc == 0
+ - delete_drive_actual_check.stdout_lines[1] == "Remote name \\\\{{ansible_hostname}}\\{{test_win_mapped_drive_path2}}"
+
+- name: delete mapped drive
+ win_mapped_drive:
+ letter: '{{test_win_mapped_drive_letter}}'
+ path: \\{{ansible_hostname}}\{{test_win_mapped_drive_path2}}
+ state: absent
+ register: delete_drive
+
+- name: get actual of delete mapped drive
+ ansible.windows.win_command: 'net use {{test_win_mapped_drive_letter}}:'
+ register: delete_drive_actual
+ failed_when: False
+
+- name: assert delete mapped drive
+ assert:
+ that:
+ - delete_drive is changed
+ - delete_drive_actual.rc == 2
+
+- name: delete mapped drive again
+ win_mapped_drive:
+ letter: '{{test_win_mapped_drive_letter}}'
+ path: \\{{ansible_hostname}}\{{test_win_mapped_drive_path2}}
+ state: absent
+ register: delete_drive_again
+
+- name: assert delete mapped drive again
+ assert:
+ that:
+ - delete_drive_again is not changed
+
+# not much we can do to test out the credentials except that it sets it, winrm
+# makes it hard to actually test out we can still access the mapped drive
+- name: map drive with current credentials check
+ win_mapped_drive:
+ letter: '{{test_win_mapped_drive_letter}}'
+ path: \\{{ansible_hostname}}\{{test_win_mapped_drive_path}}
+ state: present
+ username: '{{ansible_hostname}}\{{test_win_mapped_drive_temp_user}}'
+ password: '{{test_win_mapped_drive_temp_password}}'
+ register: map_with_credentials_check
+ check_mode: yes
+
+- name: get actual of map drive with current credentials check
+ ansible.windows.win_command: 'net use {{test_win_mapped_drive_letter}}:'
+ register: map_with_credentials_actual_check
+ failed_when: False
+
+- name: assert map drive with current credentials check
+ assert:
+ that:
+ - map_with_credentials_check is changed
+ - map_with_credentials_actual_check.rc == 2
+
+- name: map drive with current credentials
+ win_mapped_drive:
+ letter: '{{test_win_mapped_drive_letter}}'
+ path: \\{{ansible_hostname}}\{{test_win_mapped_drive_path}}
+ state: present
+ username: '{{ansible_hostname}}\{{test_win_mapped_drive_temp_user}}'
+ password: '{{test_win_mapped_drive_temp_password}}'
+ register: map_with_credentials
+
+- name: get actual of map drive with current credentials
+ ansible.windows.win_command: 'net use {{test_win_mapped_drive_letter}}:'
+ register: map_with_credentials_actual
+
+- name: get username of mapped network drive with credentials
+ ansible.windows.win_reg_stat:
+ path: HKCU:\Network\{{test_win_mapped_drive_letter}}
+ name: UserName
+ register: map_with_credential_actual_username
+
+- name: assert map drive with current credentials
+ assert:
+ that:
+ - map_with_credentials is changed
+ - map_with_credentials_actual.rc == 0
+ - map_with_credential_actual_username.value == '' # we explicitly remove the username part in the module
+
+- name: map drive with current credentials again
+ win_mapped_drive:
+ letter: '{{test_win_mapped_drive_letter}}'
+ path: \\{{ansible_hostname}}\{{test_win_mapped_drive_path}}
+ state: present
+ username: '{{ansible_hostname}}\{{test_win_mapped_drive_temp_user}}'
+ password: '{{test_win_mapped_drive_temp_password}}'
+ register: map_with_credentials_again
+
+- name: assert map drive with current credentials again
+ assert:
+ that:
+ - not map_with_credentials_again is changed
+
+- name: delete mapped drive without path check
+ win_mapped_drive:
+ letter: '{{test_win_mapped_drive_letter}}'
+ state: absent
+ register: delete_without_path_check
+ check_mode: yes
+
+- name: get actual delete mapped drive without path check
+ ansible.windows.win_command: 'net use {{test_win_mapped_drive_letter}}:'
+ register: delete_without_path_actual_check
+
+- name: assert delete mapped drive without path check
+ assert:
+ that:
+ - delete_without_path_check is changed
+ - delete_without_path_actual_check.rc == 0
+
+- name: delete mapped drive without path
+ win_mapped_drive:
+ letter: '{{test_win_mapped_drive_letter}}'
+ state: absent
+ register: delete_without_path
+
+- name: get actual delete mapped drive without path
+ ansible.windows.win_command: 'net use {{test_win_mapped_drive_letter}}:'
+ register: delete_without_path_actual
+ failed_when: False
+
+- name: assert delete mapped drive without path check
+ assert:
+ that:
+ - delete_without_path is changed
+ - delete_without_path_actual.rc == 2
+
+- name: delete mapped drive without path again
+ win_mapped_drive:
+ letter: '{{test_win_mapped_drive_letter}}'
+ state: absent
+ register: delete_without_path_again
+
+- name: assert delete mapped drive without path check again
+ assert:
+ that:
+ - delete_without_path_again is not changed
+
+- name: store credential for test network account
+ win_credential:
+ name: '{{ ansible_hostname }}'
+ type: domain_password
+ username: '{{ test_win_mapped_drive_temp_user }}'
+ secret: '{{ test_win_mapped_drive_temp_password }}'
+ state: present
+ vars: &become_vars
+ ansible_become: yes
+ ansible_become_method: runas
+ ansible_become_user: '{{ ansible_user }}'
+ ansible_become_pass: '{{ ansible_password }}'
+
+- name: map drive with stored cred (check mode)
+ win_mapped_drive:
+ letter: '{{test_win_mapped_drive_letter}}'
+ path: \\{{ansible_hostname}}\{{test_win_mapped_drive_path}}
+ state: present
+ check_mode: yes
+ vars: *become_vars
+ register: map_with_stored_cred_check
+
+- name: get actual of map drive with stored cred (check mode)
+ ansible.windows.win_command: 'net use {{test_win_mapped_drive_letter}}:'
+ register: map_with_stored_cred_actual_check
+ failed_when: False
+
+- name: assert map drive with stored cred (check mode)
+ assert:
+ that:
+ - map_with_stored_cred_check is changed
+ - map_with_stored_cred_actual_check.rc == 2
+
+- name: map drive with stored cred
+ win_mapped_drive:
+ letter: '{{test_win_mapped_drive_letter}}'
+ path: \\{{ansible_hostname}}\{{test_win_mapped_drive_path}}
+ state: present
+ vars: *become_vars
+ register: map_with_stored_cred
+
+- name: get actual of map drive with stored cred
+ ansible.windows.win_command: 'net use {{test_win_mapped_drive_letter}}:'
+ register: map_with_stored_cred_actual
+
+- name: get username of mapped network drive with stored cred
+ ansible.windows.win_reg_stat:
+ path: HKCU:\Network\{{test_win_mapped_drive_letter}}
+ name: UserName
+ register: map_with_stored_cred_actual_username
+
+- name: assert map drive with stored cred
+ assert:
+ that:
+ - map_with_stored_cred is changed
+ - map_with_stored_cred_actual.rc == 0
+ - map_with_stored_cred_actual_username.value == ''
+
+- name: map drive with stored cred again
+ win_mapped_drive:
+ letter: '{{test_win_mapped_drive_letter}}'
+ path: \\{{ansible_hostname}}\{{test_win_mapped_drive_path}}
+ state: present
+ vars: *become_vars
+ register: map_with_stored_cred_again
+
+- name: assert map drive with stored cred again
+ assert:
+ that:
+ - not map_with_stored_cred_again is changed
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_msg/aliases b/ansible_collections/community/windows/tests/integration/targets/win_msg/aliases
new file mode 100644
index 000000000..98b74ac98
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_msg/aliases
@@ -0,0 +1,2 @@
+shippable/windows/group2
+unstable
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_msg/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_msg/tasks/main.yml
new file mode 100644
index 000000000..17051239f
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_msg/tasks/main.yml
@@ -0,0 +1,33 @@
+- name: Warn user
+ win_msg:
+ display_seconds: 10
+ msg: Keep calm and carry on.
+ register: msg_result
+
+- name: Test msg_result
+ assert:
+ that:
+ - msg_result is not failed
+ - msg_result is changed
+ - msg_result.runtime_seconds < 10
+
+- name: Warn user and wait for it
+ win_msg:
+ display_seconds: 5
+ msg: Keep calm and carry on.
+ #to: '{{ ansible_user }}'
+ wait: yes
+ register: msg_wait_result
+
+- name: Test msg_wait_result
+ assert:
+ that:
+ - msg_wait_result is not failed
+ - msg_wait_result is changed
+ - msg_wait_result.runtime_seconds > 5
+
+- name: fail to send a message > 255 characters
+ win_msg:
+ msg: "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456"
+ register: fail_too_long
+ failed_when: "fail_too_long.msg != 'msg length must be less than 256 characters, current length: 256'"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_net_adapter_feature/aliases b/ansible_collections/community/windows/tests/integration/targets/win_net_adapter_feature/aliases
new file mode 100644
index 000000000..215e0b069
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_net_adapter_feature/aliases
@@ -0,0 +1 @@
+shippable/windows/group4
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_net_adapter_feature/meta/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_net_adapter_feature/meta/main.yml
new file mode 100644
index 000000000..e7f499ee3
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_net_adapter_feature/meta/main.yml
@@ -0,0 +1,2 @@
+dependencies:
+- setup_win_device \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_net_adapter_feature/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_net_adapter_feature/tasks/main.yml
new file mode 100644
index 000000000..a40e0e049
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_net_adapter_feature/tasks/main.yml
@@ -0,0 +1,27 @@
+# We create the first adapter by depending on setup_win_device but we need a 2nd one for our tests
+- name: create 2nd dummy network adapter device
+ win_device:
+ path: '%WinDir%\Inf\netloop.inf'
+ hardware_id: '*msloop'
+ state: present
+ register: network_device_name_raw2
+
+- block:
+ - set_fact:
+ network_device_name2: '{{ network_device_name_raw2.name }}'
+
+ - name: get name of the dummy network adapter
+ ansible.windows.win_shell: (Get-CimInstance -Class Win32_NetworkAdapter -Filter "Name='{{ network_device_name2 }}'").NetConnectionID
+ changed_when: False
+ register: network_adapter_name_raw2
+
+ - set_fact:
+ network_adapter_name2: '{{ network_adapter_name_raw2.stdout | trim }}'
+
+ - include_tasks: tests.yml
+
+ always:
+ - name: remove 2nd dummy network adapter device
+ win_device:
+ name: '{{ network_device_name_raw2.name }}'
+ state: absent
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_net_adapter_feature/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_net_adapter_feature/tasks/tests.yml
new file mode 100644
index 000000000..188182da3
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_net_adapter_feature/tasks/tests.yml
@@ -0,0 +1,284 @@
+- name: fail when interface isn't set
+ win_net_adapter_feature:
+ state: enabled
+ component_id: ms_tcpip6
+ register: failed_task
+ failed_when: not failed_task is failed
+
+- name: fail when component_id isn't set
+ win_net_adapter_feature:
+ interface: '{{ network_adapter_name }}'
+ state: enabled
+ register: failed_task
+ failed_when: not failed_task is failed
+
+- name: fail when interface doesn't exist
+ win_net_adapter_feature:
+ interface: Ethernet10
+ state: enabled
+ component_id: ms_tcpip6
+ register: failed_task
+ failed_when: not failed_task is failed
+
+- name: fail when state is inapppropriate
+ win_net_adapter_feature:
+ interface: '{{ network_adapter_name }}'
+ state: disabled_inappropriate
+ component_id: ms_tcpip6
+ register: failed_task
+ failed_when: not failed_task is failed
+
+- name: fail when component_id is inapppropriate
+ win_net_adapter_feature:
+ interface: '{{ network_adapter_name }}'
+ state: disabled
+ component_id: inappropriate_component
+ register: failed_task
+ failed_when: not failed_task is failed
+
+- name: disable ms_tcpip6 before execution of normal tests.
+ ansible.windows.win_shell: Disable-NetAdapterBinding -Name '{{ network_adapter_name }}' -ComponentID ms_tcpip6
+
+- name: get the status of ms_tcpip6 before execution of normal tests.
+ ansible.windows.win_shell: (Get-NetAdapterBinding -Name '{{ network_adapter_name }}' -ComponentID ms_tcpip6).Enabled
+ register: before_normal_tests
+
+- name: assert that the status of ms_tcpip6 is 'disabled' before execution of normal tests.
+ assert:
+ that:
+ - before_normal_tests.stdout_lines[0] == 'False'
+
+- name: enable an interface of ms_tpip6 when state isn't set (because the default state is 'enabled')
+ win_net_adapter_feature:
+ interface: '{{ network_adapter_name }}'
+ component_id: ms_tcpip6
+ register: enable_single
+
+- name: get the status of enable an interface of ms_tpip6
+ ansible.windows.win_shell: (Get-NetAdapterBinding -Name '{{ network_adapter_name }}' -ComponentID ms_tcpip6).Enabled
+ register: enable_single_actual
+
+- name: assert that changed is true and the status turns 'enabled'.
+ assert:
+ that:
+ - enable_single is changed
+ - enable_single_actual.stdout_lines[0] == 'True'
+
+- name: enable an interface of ms_tcpip6
+ win_net_adapter_feature:
+ interface: '{{ network_adapter_name }}'
+ state: enabled
+ component_id: ms_tcpip6
+ register: enable_single_again
+
+- name: get the status of enable an interface of ms_tcpip6
+ ansible.windows.win_shell: (Get-NetAdapterBinding -Name '{{ network_adapter_name }}' -ComponentID ms_tcpip6).Enabled
+ register: enable_single_again_actual
+
+- name: assert that changed is false and the status is still remained 'enabled'.
+ assert:
+ that:
+ - enable_single_again is not changed
+ - enable_single_again_actual.stdout_lines[0] == 'True'
+
+- name: disable an interface of ms_tcpip6
+ win_net_adapter_feature:
+ interface: '{{ network_adapter_name }}'
+ state: disabled
+ component_id: ms_tcpip6
+ register: disable_single
+
+- name: get the status of disable an interface of ms_tcpip6
+ ansible.windows.win_shell: (Get-NetAdapterBinding -Name '{{ network_adapter_name }}' -ComponentID ms_tcpip6).Enabled
+ register: disable_single_actual
+
+- name: assert that changed is true and the status turns 'disabled'.
+ assert:
+ that:
+ - disable_single is changed
+ - disable_single_actual.stdout_lines[0] == 'False'
+
+- name: enable single component_id of multiple interface
+ win_net_adapter_feature:
+ interface:
+ - '{{ network_adapter_name }}'
+ - '{{ network_adapter_name2 }}'
+ state: enabled
+ component_id: ms_tcpip6
+ register: enable_multiple
+
+- name: get the status of disable multiple interfaces of multiple interfaces - check mode
+ ansible.windows.win_shell: |
+ $info = Get-NetAdapterBinding -Name '{{ network_adapter_name }}', '{{ network_adapter_name2 }}'
+ @{
+ '{{ network_adapter_name }}' = @{
+ ms_tcpip6 = ($info | Where-Object { $_.Name -eq '{{ network_adapter_name }}' -and $_.ComponentID -eq 'ms_tcpip6'}).Enabled
+ }
+ '{{ network_adapter_name2 }}' = @{
+ ms_tcpip6 = ($info | Where-Object { $_.Name -eq '{{ network_adapter_name2 }}' -and $_.ComponentID -eq 'ms_tcpip6'}).Enabled
+ }
+ } | ConvertTo-Json
+ register: enable_multiple_actual
+
+- name: assert that changed is true and each status turns 'enabled'.
+ assert:
+ that:
+ - enable_multiple is changed
+ - (enable_multiple_actual.stdout | from_json)[network_adapter_name]['ms_tcpip6'] == True
+ - (enable_multiple_actual.stdout | from_json)[network_adapter_name2]['ms_tcpip6'] == True
+
+- name: disable multiple component_id of multiple interfaces
+ win_net_adapter_feature:
+ interface:
+ - '{{ network_adapter_name }}'
+ - '{{ network_adapter_name2 }}'
+ state: disabled
+ component_id:
+ - ms_tcpip6
+ - ms_server
+ register: mutliple_multiple_disable
+
+- name: get the status of disable multiple component_id of multiple interfaces
+ ansible.windows.win_shell: |
+ $info = Get-NetAdapterBinding -Name '{{ network_adapter_name }}', '{{ network_adapter_name2 }}'
+ @{
+ '{{ network_adapter_name }}' = @{
+ ms_tcpip6 = ($info | Where-Object { $_.Name -eq '{{ network_adapter_name }}' -and $_.ComponentID -eq 'ms_tcpip6'}).Enabled
+ ms_server = ($info | Where-Object { $_.Name -eq '{{ network_adapter_name }}' -and $_.ComponentID -eq 'ms_server'}).Enabled
+ }
+ '{{ network_adapter_name2 }}' = @{
+ ms_tcpip6 = ($info | Where-Object { $_.Name -eq '{{ network_adapter_name2 }}' -and $_.ComponentID -eq 'ms_tcpip6'}).Enabled
+ ms_server = ($info | Where-Object { $_.Name -eq '{{ network_adapter_name2 }}' -and $_.ComponentID -eq 'ms_server'}).Enabled
+ }
+ } | ConvertTo-Json
+ register: mutliple_multiple_disable_actual
+
+- name: assert that changed is true and each status turns 'disabled'.
+ assert:
+ that:
+ - mutliple_multiple_disable is changed
+ - (mutliple_multiple_disable_actual.stdout | from_json)[network_adapter_name]['ms_tcpip6'] == False
+ - (mutliple_multiple_disable_actual.stdout | from_json)[network_adapter_name]['ms_server'] == False
+ - (mutliple_multiple_disable_actual.stdout | from_json)[network_adapter_name2]['ms_tcpip6'] == False
+ - (mutliple_multiple_disable_actual.stdout | from_json)[network_adapter_name2]['ms_server'] == False
+
+- name: enable multiple interfaces of multiple interfaces
+ win_net_adapter_feature:
+ interface:
+ - '{{ network_adapter_name }}'
+ - '{{ network_adapter_name2 }}'
+ state: enabled
+ component_id:
+ - ms_tcpip6
+ - ms_server
+ register: multiple_multiple_enable
+
+- name: get the status of disable multiple component_id of multiple interfaces
+ ansible.windows.win_shell: |
+ $info = Get-NetAdapterBinding -Name '{{ network_adapter_name }}', '{{ network_adapter_name2 }}'
+ @{
+ '{{ network_adapter_name }}' = @{
+ ms_tcpip6 = ($info | Where-Object { $_.Name -eq '{{ network_adapter_name }}' -and $_.ComponentID -eq 'ms_tcpip6'}).Enabled
+ ms_server = ($info | Where-Object { $_.Name -eq '{{ network_adapter_name }}' -and $_.ComponentID -eq 'ms_server'}).Enabled
+ }
+ '{{ network_adapter_name2 }}' = @{
+ ms_tcpip6 = ($info | Where-Object { $_.Name -eq '{{ network_adapter_name2 }}' -and $_.ComponentID -eq 'ms_tcpip6'}).Enabled
+ ms_server = ($info | Where-Object { $_.Name -eq '{{ network_adapter_name2 }}' -and $_.ComponentID -eq 'ms_server'}).Enabled
+ }
+ } | ConvertTo-Json
+ register: multiple_multiple_enable_actual
+
+- name: assert that changed is true and each status turns 'enabled'.
+ assert:
+ that:
+ - multiple_multiple_enable is changed
+ - (multiple_multiple_enable_actual.stdout | from_json)[network_adapter_name]['ms_tcpip6'] == True
+ - (multiple_multiple_enable_actual.stdout | from_json)[network_adapter_name]['ms_server'] == True
+ - (multiple_multiple_enable_actual.stdout | from_json)[network_adapter_name2]['ms_tcpip6'] == True
+ - (multiple_multiple_enable_actual.stdout | from_json)[network_adapter_name2]['ms_server'] == True
+
+- name: enable multiple interfaces of multiple interfaces - idempotent
+ win_net_adapter_feature:
+ interface:
+ - '{{ network_adapter_name }}'
+ - '{{ network_adapter_name2 }}'
+ state: enabled
+ component_id:
+ - ms_tcpip6
+ - ms_server
+ register: multiple_multiple_enable_again
+
+- name: assert that changed is true and each status turns 'enabled'.
+ assert:
+ that:
+ - multiple_multiple_enable_again is not changed
+
+- name: disable multiple interfaces of multiple interfaces - check mode
+ win_net_adapter_feature:
+ interface:
+ - '{{ network_adapter_name }}'
+ - '{{ network_adapter_name2 }}'
+ state: disabled
+ component_id:
+ - ms_tcpip6
+ - ms_server
+ check_mode: yes
+ register: mutliple_multiple_disable_check
+
+- name: get the status of disable multiple interfaces of multiple interfaces - check mode
+ ansible.windows.win_shell: |
+ $info = Get-NetAdapterBinding -Name '{{ network_adapter_name }}', '{{ network_adapter_name2 }}'
+ @{
+ '{{ network_adapter_name }}' = @{
+ ms_tcpip6 = ($info | Where-Object { $_.Name -eq '{{ network_adapter_name }}' -and $_.ComponentID -eq 'ms_tcpip6'}).Enabled
+ ms_server = ($info | Where-Object { $_.Name -eq '{{ network_adapter_name }}' -and $_.ComponentID -eq 'ms_server'}).Enabled
+ }
+ '{{ network_adapter_name2 }}' = @{
+ ms_tcpip6 = ($info | Where-Object { $_.Name -eq '{{ network_adapter_name2 }}' -and $_.ComponentID -eq 'ms_tcpip6'}).Enabled
+ ms_server = ($info | Where-Object { $_.Name -eq '{{ network_adapter_name2 }}' -and $_.ComponentID -eq 'ms_server'}).Enabled
+ }
+ } | ConvertTo-Json
+ register: mutliple_multiple_disable_check_actual
+
+- name: assert disable multiple interfaces of multiple interfaces - check mode
+ assert:
+ that:
+ - mutliple_multiple_disable_check is changed
+ - (mutliple_multiple_disable_check_actual.stdout | from_json)[network_adapter_name]['ms_tcpip6'] == True
+ - (mutliple_multiple_disable_check_actual.stdout | from_json)[network_adapter_name]['ms_server'] == True
+ - (mutliple_multiple_disable_check_actual.stdout | from_json)[network_adapter_name2]['ms_tcpip6'] == True
+ - (mutliple_multiple_disable_check_actual.stdout | from_json)[network_adapter_name2]['ms_server'] == True
+
+- name: disable all the interfaces of ms_tcpip6
+ win_net_adapter_feature:
+ interface: '*'
+ state: disabled
+ component_id: ms_tcpip6
+ register: disable_all
+
+- name: get the status of disable all the interfaces of ms_tcpip6
+ ansible.windows.win_shell: (Get-NetAdapterBinding -Name * -ComponentID ms_tcpip6).Enabled -eq $true
+ register: disable_all_actual
+
+- name: assert that changed is true and each status turns 'enabled'.
+ assert:
+ that:
+ - disable_all is changed
+ - disable_all_actual.stdout_lines == []
+
+- name: enable all the interfaces of ms_tcpip6
+ win_net_adapter_feature:
+ interface: '*'
+ state: enabled
+ component_id: ms_tcpip6
+ register: enable_all
+
+- name: get the status of enable all the interfaces of ms_tcpip6
+ ansible.windows.win_shell: (Get-NetAdapterBinding -Name * -ComponentID ms_tcpip6).Enabled -eq $false
+ register: enable_all_actual
+
+- name: assert that changed is true and each status turns 'enabled'.
+ assert:
+ that:
+ - enable_all is changed
+ - enable_all_actual.stdout_lines == []
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_netbios/aliases b/ansible_collections/community/windows/tests/integration/targets/win_netbios/aliases
new file mode 100644
index 000000000..215e0b069
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_netbios/aliases
@@ -0,0 +1 @@
+shippable/windows/group4
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_netbios/meta/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_netbios/meta/main.yml
new file mode 100644
index 000000000..e7f499ee3
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_netbios/meta/main.yml
@@ -0,0 +1,2 @@
+dependencies:
+- setup_win_device \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_netbios/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_netbios/tasks/main.yml
new file mode 100644
index 000000000..2f96287bb
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_netbios/tasks/main.yml
@@ -0,0 +1,30 @@
+# Test code for win_netbios module
+# Copyright: (c) 2019, Thomas Moore <hi@tmmr.uk>
+
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+- name: ensure netbios is set to default to start with
+ win_netbios:
+ state: default
+
+- block:
+ - name: run tests
+ include_tasks: tests.yml
+
+ always:
+ - name: set netbios back to default after tests
+ win_netbios:
+ state: default \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_netbios/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_netbios/tasks/tests.yml
new file mode 100644
index 000000000..f0d7dd858
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_netbios/tasks/tests.yml
@@ -0,0 +1,159 @@
+# Test code for win_netbios module
+# Copyright: (c) 2019, Thomas Moore <hi@tmmr.uk>
+
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+- set_fact:
+ get_netbios_script: |
+ $adapter = Get-CimInstance -ClassName Win32_NetworkAdapter -Filter "NetConnectionID='{{ network_adapter_name }}'"
+ $config = Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -Filter "Index=$($adapter.DeviceID)"
+ $config.TcpipNetbiosOptions
+
+- name: disable netbios single adapter (check mode)
+ win_netbios:
+ adapter_names: '{{ network_adapter_name }}'
+ state: disabled
+ register: set_single_check
+ check_mode: yes
+
+- name: get result of disable a single adapter test (check mode)
+ ansible.windows.win_shell: '{{ get_netbios_script }}'
+ changed_when: no
+ register: set_single_actual_check
+
+- name: assert disable a single adapter (check mode)
+ assert:
+ that:
+ - set_single_check is changed
+ - set_single_actual_check.stdout_lines == ["0"]
+
+- name: disable netbios single adapter
+ win_netbios:
+ adapter_names: '{{ network_adapter_name }}'
+ state: disabled
+ register: set_single
+
+- name: get result of disable a single adapter test
+ ansible.windows.win_shell: '{{ get_netbios_script }}'
+ changed_when: no
+ register: set_single_actual
+
+- name: assert disable a single adapter
+ assert:
+ that:
+ - set_single_check is changed
+ - set_single_actual.stdout_lines == ["2"]
+
+- name: fail with invalid network adapter name
+ win_netbios:
+ state: disabled
+ adapter_names:
+ - FakeAdapterName
+ register: invalid_adapter
+ failed_when: invalid_adapter.msg != "Not all of the target adapter names could be found on the system. No configuration changes have been made. FakeAdapterName"
+
+- name: disable netbios all adapters (check mode)
+ win_netbios:
+ state: disabled
+ check_mode: yes
+ register: disable_check
+
+- name: assert disable netbios (check mode)
+ assert:
+ that:
+ - disable_check.changed
+
+- name: disable netbios all adapters
+ win_netbios:
+ state: disabled
+ register: netbios_disable
+
+- name: assert netbios disabled
+ assert:
+ that:
+ - netbios_disable.changed
+
+- name: test disable idempotence
+ win_netbios:
+ state: disabled
+ register: netbios_disable
+
+- name: test disable idempotence
+ assert:
+ that:
+ - not netbios_disable.changed
+
+- name: enable netbios all adapters (check mode)
+ win_netbios:
+ state: enabled
+ check_mode: yes
+ register: enable_check
+
+- name: assert enable netbios all adapters (check mode)
+ assert:
+ that:
+ - enable_check.changed
+
+- name: enable netbios all adapters
+ win_netbios:
+ state: enabled
+ register: netbios_enable
+
+- name: assert netbios enabled
+ assert:
+ that:
+ - netbios_enable.changed
+
+- name: test enable idempotence
+ win_netbios:
+ state: enabled
+ register: netbios_enable
+
+- name: assert enable idempotence
+ assert:
+ that:
+ - not netbios_enable.changed
+
+- name: default netbios all adapters (check mode)
+ win_netbios:
+ state: default
+ check_mode: yes
+ register: default_check
+
+- name: assert default netbios (check mode)
+ assert:
+ that:
+ - default_check.changed
+
+- name: default netbios all adapters
+ win_netbios:
+ state: default
+ register: default_enable
+
+- name: assert netbios default all adapters
+ assert:
+ that:
+ - default_enable.changed
+
+- name: test default idempotence
+ win_netbios:
+ state: default
+ register: netbios_default
+
+- name: assert default idempotence
+ assert:
+ that:
+ - not netbios_default.changed \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_nssm/aliases b/ansible_collections/community/windows/tests/integration/targets/win_nssm/aliases
new file mode 100644
index 000000000..423ce3910
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_nssm/aliases
@@ -0,0 +1 @@
+shippable/windows/group2
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_nssm/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_nssm/defaults/main.yml
new file mode 100644
index 000000000..005759965
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_nssm/defaults/main.yml
@@ -0,0 +1,4 @@
+test_service_name: ansible_nssm_test
+test_win_nssm_path: '{{ remote_tmp_dir }}\win_nssm'
+test_win_nssm_username: testnssmuser
+test_win_nssm_password: Password123! \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_nssm/meta/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_nssm/meta/main.yml
new file mode 100644
index 000000000..45806c8dc
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_nssm/meta/main.yml
@@ -0,0 +1,2 @@
+dependencies:
+- setup_remote_tmp_dir \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_nssm/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_nssm/tasks/main.yml
new file mode 100644
index 000000000..7bd4b493c
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_nssm/tasks/main.yml
@@ -0,0 +1,56 @@
+---
+- name: install NSSM
+ chocolatey.chocolatey.win_chocolatey:
+ name: NSSM
+ state: present
+
+- name: ensure testing folder exists
+ ansible.windows.win_file:
+ path: '{{test_win_nssm_path}}'
+ state: directory
+
+- name: create test user for service execution
+ ansible.windows.win_user:
+ name: '{{test_win_nssm_username}}'
+ password: '{{test_win_nssm_password}}'
+ state: present
+ groups_action: add
+ groups:
+ - Users
+ register: user_info
+
+# Run actual tests
+- block:
+ - name: normalise test account name
+ ansible.windows.win_powershell:
+ parameters:
+ SID: '{{ user_info.sid }}'
+ script: |
+ [CmdletBinding()]
+ param ([String]$SID)
+
+ $Ansible.Changed = $false
+ ([System.Security.Principal.SecurityIdentifier]$SID).Translate([System.Security.Principal.NTAccount]).Value
+ register: test_win_nssm_normalised_username
+
+ - set_fact:
+ test_win_nssm_normalised_username: '{{ test_win_nssm_normalised_username.output[0] }}'
+
+ - include_tasks: tests.yml
+
+ always:
+ - name: ensure test service is absent
+ ansible.windows.win_service:
+ name: '{{ test_service_name }}'
+ state: absent
+
+ - name: remove test user
+ ansible.windows.win_user:
+ name: '{{test_win_nssm_username}}'
+ state: absent
+
+ - name: uninstall NSSM
+ chocolatey.chocolatey.win_chocolatey:
+ name: NSSM
+ state: absent
+ failed_when: false
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_nssm/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_nssm/tasks/tests.yml
new file mode 100644
index 000000000..cf8f0cfbe
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_nssm/tasks/tests.yml
@@ -0,0 +1,615 @@
+---
+- name: get register cmd that will get service info
+ set_fact:
+ test_service_cmd: |
+ $res = @{}
+ $srvobj = Get-WmiObject Win32_Service -Filter "Name=""$service""" | Select Name,DisplayName,Description,PathName,StartMode,StartName,State
+ if ($srvobj) {
+ $srvobj | Get-Member -MemberType *Property | % { $res.($_.name) = $srvobj.($_.name) }
+
+ $startName = $res.StartName
+ $candidates = @(if ($startName -eq "LocalSystem") {
+ "NT AUTHORITY\SYSTEM"
+ }
+ elseif ($startName.Contains('\')) {
+ $nameSplit = $startName.Split('\', 2)
+
+ if ($nameSplit[0] -eq '.') {
+ ,@($env:COMPUTERNAME, $nameSplit[1])
+ $nameSplit[1]
+ } else {
+ ,$nameSplit
+ }
+ }
+ else {
+ $startName
+ })
+
+ $sid = for ($i = 0; $i -lt $candidates.Length; $i++) {
+ $candidate = $candidates[$i]
+ $ntAccount = New-Object -TypeName System.Security.Principal.NTAccount -ArgumentList $candidate
+ try {
+ $ntAccount.Translate([System.Security.Principal.SecurityIdentifier])
+ break
+ }
+ catch [System.Security.Principal.IdentityNotMappedException] {
+ if ($i -eq ($candidates.Length - 1)) {
+ throw
+ }
+ continue
+ }
+ }
+
+ $res.StartName = $sid.Translate([System.Security.Principal.NTAccount]).Value
+
+ $res.Exists = $true
+ $res.Dependencies = @(Get-WmiObject -Query "Associators of {Win32_Service.Name=""$service""} Where AssocClass=Win32_DependentService" | select -ExpandProperty Name)
+ $res.Parameters = @{}
+ $srvkey = "HKLM:\SYSTEM\CurrentControlSet\Services\$service\Parameters"
+ Get-Item "$srvkey" | Select-Object -ExpandProperty property | % { $res.Parameters.$_ = (Get-ItemProperty -Path "$srvkey" -Name $_).$_}
+ } else {
+ $res.Exists = $false
+ }
+ ConvertTo-Json -InputObject $res -Compress
+
+- name: install service (check mode)
+ win_nssm:
+ name: '{{ test_service_name }}'
+ application: C:\Windows\System32\cmd.exe
+ state: present
+ register: install_service_check
+ check_mode: yes
+
+- name: get result of install service (check mode)
+ ansible.windows.win_shell: '$service = ''{{ test_service_name }}''; {{ test_service_cmd }}'
+ register: install_service_check_actual
+
+- name: assert results of install service (check mode)
+ assert:
+ that:
+ - install_service_check.changed == true
+ - (install_service_check_actual.stdout|from_json).Exists == false
+
+- name: install service
+ win_nssm:
+ name: '{{ test_service_name }}'
+ application: C:\Windows\System32\cmd.exe
+ state: present
+ register: install_service
+
+- name: get result of install service
+ ansible.windows.win_shell: '$service = ''{{ test_service_name }}''; {{ test_service_cmd }}'
+ register: install_service_actual
+
+- name: assert results of install service
+ assert:
+ that:
+ - install_service.changed == true
+ - (install_service_actual.stdout|from_json).Exists == true
+ - (install_service_actual.stdout|from_json).State == 'Stopped'
+ - (install_service_actual.stdout|from_json).StartMode == 'Auto'
+ - (install_service_actual.stdout|from_json).Parameters.Application == "C:\Windows\System32\cmd.exe"
+ - (install_service_actual.stdout|from_json).Parameters.AppDirectory == "C:\Windows\System32"
+
+- name: test install service (idempotent)
+ win_nssm:
+ name: '{{ test_service_name }}'
+ application: C:\Windows\System32\cmd.exe
+ state: present
+ register: install_service_again
+
+- name: get result of install service (idempotent)
+ ansible.windows.win_shell: '$service = ''{{ test_service_name }}''; {{ test_service_cmd }}'
+ register: install_service_again_actual
+
+- name: assert results of install service (idempotent)
+ assert:
+ that:
+ - install_service_again.changed == false
+ - (install_service_again_actual.stdout|from_json).Exists == true
+ - (install_service_again_actual.stdout|from_json).State == 'Stopped'
+ - (install_service_again_actual.stdout|from_json).StartMode == 'Auto'
+ - (install_service_again_actual.stdout|from_json).Parameters.Application == "C:\Windows\System32\cmd.exe"
+ - (install_service_again_actual.stdout|from_json).Parameters.AppDirectory == "C:\Windows\System32"
+
+- name: install and start service
+ win_nssm:
+ name: '{{ test_service_name }}'
+ application: C:\Windows\System32\cmd.exe
+ state: started
+ register: install_start_service
+
+- name: get result of install and start service
+ ansible.windows.win_shell: '$service = ''{{ test_service_name }}''; {{ test_service_cmd }}'
+ register: install_start_service_actual
+
+- name: assert results of install and start service
+ assert:
+ that:
+ - install_start_service.changed == true
+ - (install_start_service_actual.stdout|from_json).Exists == true
+ - (install_start_service_actual.stdout|from_json).State == 'Running'
+ - (install_start_service_actual.stdout|from_json).StartMode == 'Auto'
+ - (install_start_service_actual.stdout|from_json).Parameters.Application == "C:\Windows\System32\cmd.exe"
+ - (install_start_service_actual.stdout|from_json).Parameters.AppDirectory == "C:\Windows\System32"
+
+- name: install and start service with more parameters (check mode)
+ win_nssm:
+ name: '{{ test_service_name }}'
+ display_name: Ansible testing
+ description: win_nssm test service
+ application: C:\Windows\System32\cmd.exe
+ start_mode: manual
+ working_directory: '{{ test_win_nssm_path }}'
+ dependencies: 'tcpip,dnscache'
+ username: '{{ test_win_nssm_username }}'
+ password: '{{ test_win_nssm_password }}'
+ stdout_file: '{{ test_win_nssm_path }}\log.txt'
+ stderr_file: '{{ test_win_nssm_path }}\error.txt'
+ state: started
+ register: install_service_complex_check
+ check_mode: yes
+
+- name: get result of install and start service with more parameters (check mode)
+ ansible.windows.win_shell: '$service = ''{{ test_service_name }}''; {{ test_service_cmd }}'
+ register: install_service_complex_check_actual
+
+- name: assert results of install and start service with more parameters (check mode)
+ assert:
+ that:
+ - install_service_complex_check.changed == true
+ - (install_service_complex_check_actual.stdout|from_json).Exists == true
+ - (install_service_complex_check_actual.stdout|from_json).DisplayName == '{{ test_service_name }}'
+ - (install_service_complex_check_actual.stdout|from_json).Description is none
+ - (install_service_complex_check_actual.stdout|from_json).StartMode != 'Manual'
+ - (install_service_complex_check_actual.stdout|from_json).StartName != test_win_nssm_normalised_username
+ - (install_service_complex_check_actual.stdout|from_json).Parameters.Application == "C:\Windows\System32\cmd.exe"
+ - (install_service_complex_check_actual.stdout|from_json).Parameters.AppDirectory == "C:\Windows\System32"
+ - '"AppStdout" not in (install_service_complex_check_actual.stdout|from_json).Parameters'
+ - '"AppStderr" not in (install_service_complex_check_actual.stdout|from_json).Parameters'
+ - (install_service_complex_check_actual.stdout|from_json).Dependencies|length == 0
+
+- name: install and start service with more parameters
+ win_nssm:
+ name: '{{ test_service_name }}'
+ display_name: Ansible testing
+ description: win_nssm test service
+ application: C:\Windows\System32\cmd.exe
+ start_mode: manual
+ working_directory: '{{ test_win_nssm_path }}'
+ dependencies: 'tcpip,dnscache'
+ username: '{{ test_win_nssm_username }}'
+ password: '{{ test_win_nssm_password }}'
+ stdout_file: '{{ test_win_nssm_path }}\log.txt'
+ stderr_file: '{{ test_win_nssm_path }}\error.txt'
+ state: started
+ register: install_service_complex
+
+- name: get result of install and start service with more parameters
+ ansible.windows.win_shell: '$service = ''{{ test_service_name }}''; {{ test_service_cmd }}'
+ register: install_service_complex_actual
+
+- name: assert results of install and start service with more parameters
+ assert:
+ that:
+ - install_service_complex.changed == true
+ - (install_service_complex_actual.stdout|from_json).Exists == true
+ - (install_service_complex_actual.stdout|from_json).DisplayName == 'Ansible testing'
+ - (install_service_complex_actual.stdout|from_json).Description == 'win_nssm test service'
+ - (install_service_complex_actual.stdout|from_json).State == 'Running'
+ - (install_service_complex_actual.stdout|from_json).StartMode == 'Manual'
+ - (install_service_complex_actual.stdout|from_json).StartName == test_win_nssm_normalised_username
+ - (install_service_complex_actual.stdout|from_json).Parameters.Application == "C:\Windows\System32\cmd.exe"
+ - (install_service_complex_actual.stdout|from_json).Parameters.AppDirectory == test_win_nssm_path
+ - (install_service_complex_actual.stdout|from_json).Parameters.AppStdout == test_win_nssm_path + '\\log.txt'
+ - (install_service_complex_actual.stdout|from_json).Parameters.AppStderr == test_win_nssm_path + '\\error.txt'
+ - (install_service_complex_actual.stdout|from_json).Dependencies|length == 2
+ - '"Tcpip" in (install_service_complex_actual.stdout|from_json).Dependencies'
+ - '"Dnscache" in (install_service_complex_actual.stdout|from_json).Dependencies'
+
+- name: install and start service with more parameters (idempotent)
+ win_nssm:
+ name: '{{ test_service_name }}'
+ display_name: Ansible testing
+ description: win_nssm test service
+ application: C:\Windows\System32\cmd.exe
+ start_mode: manual
+ working_directory: '{{ test_win_nssm_path }}'
+ # Dependencies order should not trigger a change
+ dependencies: 'dnscache,tcpip'
+ username: '{{ test_win_nssm_username }}'
+ password: '{{ test_win_nssm_password }}'
+ stdout_file: '{{ test_win_nssm_path }}\log.txt'
+ stderr_file: '{{ test_win_nssm_path }}\error.txt'
+ state: started
+ register: install_service_complex_again
+
+- name: get result of install and start service with more parameters (idempotent)
+ ansible.windows.win_shell: '$service = ''{{ test_service_name }}''; {{ test_service_cmd }}'
+ register: install_service_complex_again_actual
+
+- name: assert results of install and start service with more parameters (idempotent)
+ assert:
+ that:
+ - install_service_complex_again.changed == false
+ - (install_service_complex_again_actual.stdout|from_json).Exists == true
+ - (install_service_complex_again_actual.stdout|from_json).DisplayName == 'Ansible testing'
+ - (install_service_complex_again_actual.stdout|from_json).Description == 'win_nssm test service'
+ - (install_service_complex_again_actual.stdout|from_json).State == 'Running'
+ - (install_service_complex_again_actual.stdout|from_json).StartMode == 'Manual'
+ - (install_service_complex_again_actual.stdout|from_json).StartName == test_win_nssm_normalised_username
+ - (install_service_complex_again_actual.stdout|from_json).Parameters.Application == "C:\Windows\System32\cmd.exe"
+ - (install_service_complex_again_actual.stdout|from_json).Parameters.AppDirectory == test_win_nssm_path
+ - (install_service_complex_again_actual.stdout|from_json).Parameters.AppStdout == test_win_nssm_path + '\\log.txt'
+ - (install_service_complex_again_actual.stdout|from_json).Parameters.AppStderr == test_win_nssm_path + '\\error.txt'
+ - (install_service_complex_again_actual.stdout|from_json).Dependencies|length == 2
+ - '"Tcpip" in (install_service_complex_again_actual.stdout|from_json).Dependencies'
+ - '"Dnscache" in (install_service_complex_again_actual.stdout|from_json).Dependencies'
+
+- name: install service with string form parameters
+ win_nssm:
+ name: '{{ test_service_name }}'
+ application: C:\Windows\System32\cmd.exe
+ arguments: '-v -Dtest.str=value "C:\with space\\"'
+ state: present
+ register: str_params
+
+- name: get result of install service with string form parameters
+ ansible.windows.win_shell: '$service = ''{{ test_service_name }}''; {{ test_service_cmd }}'
+ register: str_params_actual
+
+- name: assert results of install service with string form parameters
+ assert:
+ that:
+ - str_params.changed == true
+ - (str_params_actual.stdout|from_json).Exists == true
+ - (str_params_actual.stdout|from_json).Parameters.Application == "C:\Windows\System32\cmd.exe"
+ # Expected value: -v -Dtest.str=value "C:\with space\\" (backslashes doubled for jinja)
+ - (str_params_actual.stdout|from_json).Parameters.AppParameters == '-v -Dtest.str=value "C:\\with space\\\\"'
+
+- name: install service with string form parameters (idempotent)
+ win_nssm:
+ name: '{{ test_service_name }}'
+ application: C:\Windows\System32\cmd.exe
+ arguments: '-v -Dtest.str=value "C:\with space\\"'
+ state: present
+ register: str_params_again
+
+- name: get result of install service with string form parameters (idempotent)
+ ansible.windows.win_shell: '$service = ''{{ test_service_name }}''; {{ test_service_cmd }}'
+ register: str_params_again_actual
+
+- name: assert results of install service with string form parameters (idempotent)
+ assert:
+ that:
+ - str_params_again.changed == false
+ - (str_params_again_actual.stdout|from_json).Exists == true
+ - (str_params_again_actual.stdout|from_json).Parameters.Application == "C:\Windows\System32\cmd.exe"
+ # Expected value: -v -Dtest.str=value "C:\with space\\" (backslashes doubled for jinja)
+ - (str_params_again_actual.stdout|from_json).Parameters.AppParameters == '-v -Dtest.str=value "C:\\with space\\\\"'
+
+- name: install service with extra environment vars (check mode)
+ win_nssm:
+ name: '{{ test_service_name }}'
+ application: C:\Windows\System32\cmd.exe
+ start_mode: manual
+ state: present
+ app_environment:
+ foo: bar
+ baz: 2
+ register: install_service_appenv_check
+ check_mode: yes
+
+- name: get result of install service with extra environment vars (check mode)
+ ansible.windows.win_shell: nssm.exe get '{{ test_service_name }}' AppEnvironmentExtra
+ register: install_service_appenv_check_actual
+
+ ## note: this could fail (in theory) when the service is not yet
+ ## installed (diff mode), but because of side effects of earlier
+ ## tests this will actually not fail in practice, however, it is
+ ## not a real issue in any case
+ failed_when: false
+
+- name: assert results of install service with extra environment vars (check mode)
+ assert:
+ that:
+ - install_service_appenv_check.changed == true
+ - install_service_appenv_check_actual.stdout == '\r\n' or install_service_appenv_check_actual.stdout == ''
+
+- name: install service with extra environment vars
+ win_nssm:
+ name: '{{ test_service_name }}'
+ application: C:\Windows\System32\cmd.exe
+ start_mode: manual
+ state: present
+ app_environment:
+ foo: bar
+ baz: 2
+ register: install_service_appenv
+
+- name: get result of install service with extra environment vars
+ ansible.windows.win_shell: nssm.exe get '{{ test_service_name }}' AppEnvironmentExtra
+ register: install_service_appenv_actual
+
+- name: assert results of install service with extra environment vars
+ assert:
+ that:
+ - install_service_appenv.changed == true
+ - (install_service_appenv_actual.stdout_lines|length) == 3
+ - (install_service_appenv_actual.stdout_lines[0]) == 'baz=2'
+ - (install_service_appenv_actual.stdout_lines[2]) == 'foo=bar'
+
+- name: install service with extra environment vars (idempotent)
+ win_nssm:
+ name: '{{ test_service_name }}'
+ application: C:\Windows\System32\cmd.exe
+ start_mode: manual
+ state: present
+ app_environment:
+ foo: bar
+ baz: 2
+ register: install_service_appenv_idem
+
+- name: get result of install service with extra environment vars (idempotent)
+ ansible.windows.win_shell: nssm.exe get '{{ test_service_name }}' AppEnvironmentExtra
+ register: install_service_appenv_idem_actual
+
+- name: assert results of install service with extra environment vars (idempotent)
+ assert:
+ that:
+ - install_service_appenv_idem.changed == false
+ - (install_service_appenv_idem_actual.stdout_lines|length) == 3
+ - (install_service_appenv_idem_actual.stdout_lines[0]) == 'baz=2'
+ - (install_service_appenv_idem_actual.stdout_lines[2]) == 'foo=bar'
+
+- name: install service dont change app_env if not explicitly requested
+ win_nssm:
+ name: '{{ test_service_name }}'
+ application: C:\Windows\System32\cmd.exe
+ start_mode: manual
+ state: present
+ register: install_service_appenv_implicit
+
+- name: get result of install service dont change app_env if not explicitly requested
+ ansible.windows.win_shell: nssm.exe get '{{ test_service_name }}' AppEnvironmentExtra
+ register: install_service_appenv_implicit_actual
+
+- name: assert results of install service dont change app_env if not explicitly requested
+ assert:
+ that:
+ - install_service_appenv_implicit.changed == false
+ - (install_service_appenv_implicit_actual.stdout_lines|length) == 3
+ - (install_service_appenv_implicit_actual.stdout_lines[0]) == 'baz=2'
+ - (install_service_appenv_implicit_actual.stdout_lines[2]) == 'foo=bar'
+
+- name: install service resetting env vars
+ win_nssm:
+ name: '{{ test_service_name }}'
+ application: C:\Windows\System32\cmd.exe
+ start_mode: manual
+ state: present
+ app_environment: {}
+ register: install_service_reset_appenv
+
+- name: get result of install service resetting env vars
+ ansible.windows.win_shell: nssm.exe get '{{ test_service_name }}' AppEnvironmentExtra
+ register: install_service_reset_appenv_actual
+
+- name: assert results of install service resetting env vars
+ assert:
+ that:
+ - install_service_reset_appenv.changed == true
+ - install_service_reset_appenv_actual.stdout == '\r\n'
+
+# deprecated in 2.12
+- name: install service with dict-as-string parameters
+ win_nssm:
+ name: '{{ test_service_name }}'
+ application: C:\Windows\System32\cmd.exe
+ app_parameters: foo=true; -file.out=output.bat; -path=C:\with space\; -str=test"quotes; _=bar
+ register: mixed_params
+
+# deprecated in 2.12
+- name: get result of install service with dict-as-string parameters
+ ansible.windows.win_shell: '$service = ''{{ test_service_name }}''; {{ test_service_cmd }}'
+ register: mixed_params_actual
+
+# deprecated in 2.12
+- name: assert results of install service with dict-as-string parameters
+ assert:
+ that:
+ - mixed_params.changed == true
+ - (mixed_params_actual.stdout|from_json).Exists == true
+ - (mixed_params_actual.stdout|from_json).Parameters.Application == "C:\Windows\System32\cmd.exe"
+ # Expected value: bar -file.out output.bat -str "test\"quotes" foo true -path "C:\with space\\" (backslashes doubled for jinja)
+ - (mixed_params_actual.stdout|from_json).Parameters.AppParameters == 'bar -file.out output.bat -str "test\\"quotes" foo true -path "C:\\with space\\\\"'
+
+# deprecated in 2.12
+- name: install service with dict-as-string parameters (idempotent)
+ win_nssm:
+ name: '{{ test_service_name }}'
+ application: C:\Windows\System32\cmd.exe
+ app_parameters: foo=true; -file.out=output.bat; -path=C:\with space\; -str=test"quotes; _=bar
+ register: mixed_params_again
+
+# deprecated in 2.12
+- name: get result of install service with dict-as-string parameters (idempotent)
+ ansible.windows.win_shell: '$service = ''{{ test_service_name }}''; {{ test_service_cmd }}'
+ register: mixed_params_again_actual
+
+# deprecated in 2.12
+- name: assert results of install service with dict-as-string parameters (idempotent)
+ assert:
+ that:
+ - mixed_params_again.changed == false
+ - (mixed_params_again_actual.stdout|from_json).Exists == true
+ - (mixed_params_again_actual.stdout|from_json).Parameters.Application == "C:\Windows\System32\cmd.exe"
+ # Expected value: bar -file.out output.bat -str "test\"quotes" foo true -path "C:\with space\\" (backslashes doubled for jinja)
+ - (mixed_params_again_actual.stdout|from_json).Parameters.AppParameters == 'bar -file.out output.bat -str "test\\"quotes" foo true -path "C:\\with space\\\\"'
+
+- name: install service with list of parameters
+ win_nssm:
+ name: '{{ test_service_name }}'
+ application: C:\Windows\System32\cmd.exe
+ arguments:
+ - -foo=bar
+ - -day
+ # Test non-string value
+ - 14
+ # Test if dot is not interpreted as separator (see #44079)
+ - -file.out
+ # Test if spaces are escaped
+ - C:\with space\output.bat
+ - -str
+ # Test if quotes and backslashes are escaped
+ - test"quotes\
+ register: list_params
+
+- name: get result of install service with list of parameters
+ ansible.windows.win_shell: '$service = ''{{ test_service_name }}''; {{ test_service_cmd }}'
+ register: list_params_actual
+
+- name: assert results of install service with list of parameters
+ assert:
+ that:
+ - list_params.changed == true
+ - (list_params_actual.stdout|from_json).Exists == true
+ - (list_params_actual.stdout|from_json).Parameters.Application == "C:\Windows\System32\cmd.exe"
+ # Expected value: -foo=bar -day 14 -file.out "C:\with space\output.bat" -str "test\"quotes\\" (backslashes doubled for jinja)
+ - (list_params_actual.stdout|from_json).Parameters.AppParameters == '-foo=bar -day 14 -file.out "C:\\with space\\output.bat" -str "test\\"quotes\\\\"'
+
+- name: install service with list of parameters (idempotent)
+ win_nssm:
+ name: '{{ test_service_name }}'
+ application: C:\Windows\System32\cmd.exe
+ arguments:
+ - -foo=bar
+ - -day
+ - 14
+ - -file.out
+ - C:\with space\output.bat
+ - -str
+ - test"quotes\
+ register: list_params_again
+
+- name: get result of install service with list of parameters (idempotent)
+ ansible.windows.win_shell: '$service = ''{{ test_service_name }}''; {{ test_service_cmd }}'
+ register: list_params_again_actual
+
+- name: assert results of install service with list of parameters (idempotent)
+ assert:
+ that:
+ - list_params_again.changed == false
+ - (list_params_again_actual.stdout|from_json).Exists == true
+ - (list_params_again_actual.stdout|from_json).Parameters.Application == "C:\Windows\System32\cmd.exe"
+ # Expected value: -foo=bar -day 14 -file.out "C:\with space\output.bat" -str "test\"quotes\\" (backslashes doubled for jinja)
+ - (list_params_again_actual.stdout|from_json).Parameters.AppParameters == '-foo=bar -day 14 -file.out "C:\\with space\\output.bat" -str "test\\"quotes\\\\"'
+
+- name: set service username to SYSTEM
+ win_nssm:
+ name: '{{ test_service_name }}'
+ username: LocalSystem
+ application: C:\Windows\System32\cmd.exe
+ register: service_system
+
+- name: get service account for SYSTEM
+ ansible.windows.win_service_info:
+ name: '{{ test_service_name }}'
+ register: service_system_actual
+
+- name: assert set service username to SYSTEM
+ assert:
+ that:
+ - service_system is changed
+ - service_system_actual.services[0].username == 'NT AUTHORITY\\SYSTEM'
+
+- name: set service username to SYSTEM (idempotent)
+ win_nssm:
+ name: '{{ test_service_name }}'
+ username: SYSTEM
+ application: C:\Windows\System32\cmd.exe
+ register: service_system_again
+
+- name: assert set service username to SYSTEM (idempotent)
+ assert:
+ that:
+ - not service_system_again is changed
+
+- name: set service username to NETWORK SERVICE
+ win_nssm:
+ name: '{{ test_service_name }}'
+ username: NETWORK SERVICE
+ application: C:\Windows\System32\cmd.exe
+ register: service_network
+
+- name: get service account for NETWORK SERVICE
+ ansible.windows.win_service_info:
+ name: '{{ test_service_name }}'
+ register: service_network_actual
+
+- name: assert set service username to NETWORK SERVICE
+ assert:
+ that:
+ - service_network is changed
+ - service_network_actual.services[0].username == 'NT Authority\\NetworkService'
+
+- name: set service username to NETWORK SERVICE (idempotent)
+ win_nssm:
+ name: '{{ test_service_name }}'
+ username: NT AUTHORITY\NETWORK SERVICE
+ application: C:\Windows\System32\cmd.exe
+ register: service_network_again
+
+- name: assert set service username to NETWORK SERVICE (idempotent)
+ assert:
+ that:
+ - not service_network_again is changed
+
+- name: remove service (check mode)
+ win_nssm:
+ name: '{{ test_service_name }}'
+ state: absent
+ register: remove_service_check
+ check_mode: yes
+
+- name: get result of remove service (check mode)
+ ansible.windows.win_shell: '$service = ''{{ test_service_name }}''; {{ test_service_cmd }}'
+ register: remove_service_check_actual
+
+- name: assert results of remove service (check mode)
+ assert:
+ that:
+ - remove_service_check.changed == true
+ - (remove_service_check_actual.stdout|from_json).Exists == true
+
+- name: remove service
+ win_nssm:
+ name: '{{ test_service_name }}'
+ state: absent
+ register: remove_service
+
+- name: get result of remove service
+ ansible.windows.win_shell: '$service = ''{{ test_service_name }}''; {{ test_service_cmd }}'
+ register: remove_service_actual
+
+- name: assert results of remove service
+ assert:
+ that:
+ - remove_service.changed == true
+ - (remove_service_actual.stdout|from_json).Exists == false
+
+- name: remove service (idempotent)
+ win_nssm:
+ name: '{{ test_service_name }}'
+ state: absent
+ register: remove_service_again
+
+- name: get result of remove service (idempotent)
+ ansible.windows.win_shell: '$service = ''{{ test_service_name }}''; {{ test_service_cmd }}'
+ register: remove_service_again_actual
+
+- name: assert results of remove service (idempotent)
+ assert:
+ that:
+ - remove_service_again.changed == false
+ - (remove_service_again_actual.stdout|from_json).Exists == false
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_pagefile/aliases b/ansible_collections/community/windows/tests/integration/targets/win_pagefile/aliases
new file mode 100644
index 000000000..a4da730ea
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_pagefile/aliases
@@ -0,0 +1,2 @@
+shippable/windows/group3
+unstable
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_pagefile/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_pagefile/tasks/main.yml
new file mode 100644
index 000000000..0cde27bfa
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_pagefile/tasks/main.yml
@@ -0,0 +1,241 @@
+---
+# Get current pagefiles status
+- name: Get original pagefile settings
+ win_pagefile:
+ state: query
+ register: original_pagefile_settings
+
+# Remove all original pagefiles
+- name: Remove all original pagefiles
+ win_pagefile:
+ remove_all: true
+ register: remove_all_pagefiles
+
+# Test 1: Set c pagefile with inital and maximum size
+- name: Set C pagefile as 1024-2048MB
+ win_pagefile:
+ remove_all: yes
+ drive: C
+ initial_size: 1024
+ maximum_size: 2048
+ override: yes
+ state: present
+ register: c_pagefile
+
+- name: Test set c pagefile
+ assert:
+ that:
+ - c_pagefile.changed == true
+
+- name: Query all pagefiles
+ win_pagefile:
+ state: query
+ register: pagefiles_query
+
+- name: Set fact for pagefile expected result
+ set_fact:
+ expected:
+ pagefiles:
+ - caption: "C:\\ 'pagefile.sys'"
+ description: "'pagefile.sys' @ C:\\"
+ initial_size: 1024
+ maximum_size: 2048
+ name: "C:\\pagefile.sys"
+
+- name: Test query - c pagefile 1024-2048
+ assert:
+ that:
+ - pagefiles_query.changed == false
+ - pagefiles_query.pagefiles == expected.pagefiles
+ - pagefiles_query.automatic_managed_pagefiles == false
+
+
+# Test 2: Remove c pagefile
+- name: Remove C pagefile
+ win_pagefile:
+ drive: C
+ state: absent
+ register: delete_c_pagefile
+
+- name: Test removal of c pagefile
+ assert:
+ that:
+ - delete_c_pagefile.changed == true
+
+- name: Query all pagefiles
+ win_pagefile:
+ state: query
+ register: pagefiles_query
+
+- name: Set fact for pagefile expected result
+ set_fact:
+ expected:
+ pagefiles: []
+
+- name: Test query - no c pagefile
+ assert:
+ that:
+ - pagefiles_query.changed == false
+ - pagefiles_query.pagefiles == expected.pagefiles
+ - pagefiles_query.automatic_managed_pagefiles == false
+
+
+# Test 3: Set automatic managed pagefile as true
+- name: Set automatic managed pagefiles as true
+ win_pagefile:
+ automatic: yes
+ register: set_automatic_true
+
+- name: Test removal of c pagefile
+ assert:
+ that:
+ - set_automatic_true.changed == true
+ - set_automatic_true.automatic_managed_pagefiles == true
+
+
+# Test 4: Set c pagefile as system managed pagefile
+- name: Set c pagefile as system managed pagefile
+ win_pagefile:
+ drive: C
+ system_managed: yes
+ state: present
+ register: c_pagefile_system_managed
+
+- name: Test set c pagefile as system managed
+ assert:
+ that:
+ - c_pagefile_system_managed.changed == true
+
+- name: Query all pagefiles
+ win_pagefile:
+ state: query
+ register: pagefiles_query
+
+- name: Set fact for pagefile expected result
+ set_fact:
+ expected:
+ pagefiles:
+ - caption: "C:\\ 'pagefile.sys'"
+ description: "'pagefile.sys' @ C:\\"
+ initial_size: 0
+ maximum_size: 0
+ name: "C:\\pagefile.sys"
+
+- name: Test query - c pagefile 0-0 (system managed)
+ assert:
+ that:
+ - pagefiles_query.changed == false
+ - pagefiles_query.pagefiles == expected.pagefiles
+ - pagefiles_query.automatic_managed_pagefiles == false
+
+# Test 5: Test no override
+- name: Set c pagefile 1024-1024, no override
+ win_pagefile:
+ drive: C
+ initial_size: 1024
+ maximum_size: 1024
+ override: no
+ state: present
+ register: c_pagefile_no_override
+
+- name: Test set c pagefile no override
+ assert:
+ that:
+ - c_pagefile_no_override.changed == false
+
+- name: Query all pagefiles
+ win_pagefile:
+ state: query
+ register: pagefiles_query
+
+- name: Test query - c pagefile unchanged
+ assert:
+ that:
+ - pagefiles_query.changed == false
+ - pagefiles_query.pagefiles == expected.pagefiles
+ - pagefiles_query.automatic_managed_pagefiles == false
+
+
+# Test 6: Test override
+- name: Set c pagefile 1024-1024, override
+ win_pagefile:
+ drive: C
+ initial_size: 1024
+ maximum_size: 1024
+ state: present
+ register: c_pagefile_override
+
+- name: Test set c pagefile no override
+ assert:
+ that:
+ - c_pagefile_override.changed == true
+
+ # Test 7: Test idempotent
+- name: Set c pagefile 1024-1024, idempotent
+ win_pagefile:
+ drive: C
+ initial_size: 1024
+ maximum_size: 1024
+ override: no
+ state: present
+ register: c_pagefile_idempotent
+
+- name: Test set c pagefile idempotent
+ assert:
+ that:
+ - c_pagefile_idempotent.changed == false
+
+- name: Query all pagefiles
+ win_pagefile:
+ state: query
+ register: pagefiles_query
+
+- name: Set fact for pagefile expected result
+ set_fact:
+ expected:
+ pagefiles:
+ - caption: "C:\\ 'pagefile.sys'"
+ description: "'pagefile.sys' @ C:\\"
+ initial_size: 1024
+ maximum_size: 1024
+ name: "C:\\pagefile.sys"
+
+- name: Test query - c pagefile 1024-1024
+ assert:
+ that:
+ - pagefiles_query.changed == false
+ - pagefiles_query.pagefiles == expected.pagefiles
+ - pagefiles_query.automatic_managed_pagefiles == false
+
+# Test 7: Remove all pagefiles
+- name: Remove all pagefiles
+ win_pagefile:
+ remove_all: true
+ register: remove_all_pagefiles
+
+- name: Set fact for pagefile expected result
+ set_fact:
+ expected:
+ pagefiles: []
+
+- name: Test query - no pagefiles
+ assert:
+ that:
+ - remove_all_pagefiles.changed == true
+ - remove_all_pagefiles.pagefiles == expected.pagefiles
+ - pagefiles_query.automatic_managed_pagefiles == false
+
+# Return all pagefile settings to its original state
+- name: Remove all pagefiles and return automatic to its original state
+ win_pagefile:
+ remove_all: yes
+ automatic: "{{ original_pagefile_settings.automatic_managed_pagefiles }}"
+
+- name: Return all previous pagefiles settings
+ win_pagefile:
+ drive: "{{ item.name[0] }}"
+ initial_size: "{{ item.initial_size }}"
+ maximum_size: "{{ item.maximum_size }}"
+ test_path: no
+ state: present
+ with_items: "{{ original_pagefile_settings.pagefiles }}"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_partition/aliases b/ansible_collections/community/windows/tests/integration/targets/win_partition/aliases
new file mode 100644
index 000000000..4cd27b3cb
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_partition/aliases
@@ -0,0 +1 @@
+shippable/windows/group1
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_partition/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_partition/defaults/main.yml
new file mode 100644
index 000000000..ca221d09b
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_partition/defaults/main.yml
@@ -0,0 +1 @@
+AnsibleVhdx: '{{ remote_tmp_dir }}\AnsiblePart.vhdx'
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_partition/meta/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_partition/meta/main.yml
new file mode 100644
index 000000000..45806c8dc
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_partition/meta/main.yml
@@ -0,0 +1,2 @@
+dependencies:
+- setup_remote_tmp_dir \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_partition/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_partition/tasks/main.yml
new file mode 100644
index 000000000..50d086ae1
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_partition/tasks/main.yml
@@ -0,0 +1,18 @@
+---
+- name: Copy VHDX scripts
+ ansible.windows.win_template:
+ src: "{{ item.src }}"
+ dest: '{{ remote_tmp_dir }}\{{ item.dest }}'
+ loop:
+ - { src: vhdx_creation_script.j2, dest: vhdx_creation_script.txt }
+ - { src: vhdx_deletion_script.j2, dest: vhdx_deletion_script.txt }
+
+- name: Create VHD
+ ansible.windows.win_command: diskpart.exe /s "{{ remote_tmp_dir }}\vhdx_creation_script.txt"
+
+- name: Run tests
+ block:
+ - include: tests.yml
+ always:
+ - name: Detach disk
+ ansible.windows.win_command: diskpart.exe /s "{{ remote_tmp_dir }}\vhdx_deletion_script.txt"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_partition/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_partition/tasks/tests.yml
new file mode 100644
index 000000000..83f189a6b
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_partition/tasks/tests.yml
@@ -0,0 +1,261 @@
+---
+- name: Since partition is not present, disk_number is required to create a new partition.
+ win_partition:
+ drive_letter: D
+ register: incorrect_attempt_1
+ ignore_errors: True
+
+- assert:
+ that:
+ - incorrect_attempt_1 is failed
+ - '"Missing required parameter: disk_number" in incorrect_attempt_1.msg'
+
+- name: Added disk_number but size is still absent
+ win_partition:
+ drive_letter: D
+ disk_number: 0
+ register: incorrect_attempt_2
+ ignore_errors: True
+
+- assert:
+ that:
+ - incorrect_attempt_2 is failed
+ - '"Missing required parameter: partition_size" in incorrect_attempt_2.msg'
+
+- name: Added size but the disk we specified earlier doesn't have enough space
+ win_partition:
+ drive_letter: D
+ disk_number: 1
+ partition_size: 20 GiB
+ register: incorrect_attempt_3
+ ignore_errors: True
+
+- assert:
+ that:
+ - incorrect_attempt_3 is failed
+ - '"Partition size is not supported by disk" in incorrect_attempt_3.msg'
+
+- name: Create 1 gib partition using drive_letter and default (huge) mbr type (check mode)
+ win_partition:
+ drive_letter: D
+ state: present
+ partition_size: 1 GiB
+ disk_number: 1
+ active: True
+ register: create_small_part_check
+ check_mode: True
+
+- name: Create 1 gib partition using drive_letter and default (huge) mbr type
+ win_partition:
+ drive_letter: D
+ state: present
+ partition_size: 1 GiB
+ disk_number: 1
+ active: True
+ register: create_small_part
+
+- name: Create 1 gib partition using drive_letter and default (huge) mbr type (idempotence)
+ win_partition:
+ drive_letter: D
+ state: present
+ partition_size: 1 GiB
+ disk_number: 1
+ active: True
+ register: create_small_part_idempotence
+
+- name: "Check if partition was created successfully"
+ ansible.windows.win_shell: $AnsiPart = Get-Partition -DriveLetter D; "$($AnsiPart.DriveLetter),$($AnsiPart.Size),$($AnsiPart.IsActive),$($AnsiPart.MbrType)"
+ register: get_small_part
+
+- assert:
+ that:
+ - create_small_part_check is changed
+ - create_small_part is changed
+ - create_small_part_idempotence is not changed
+ - get_small_part.stdout | trim == "D,1073741824,True,6"
+
+- name: "Change drive letter, maximize partition size and set partition to read only (check mode)"
+ win_partition:
+ drive_letter: E
+ state: present
+ partition_size: -1
+ disk_number: 1
+ partition_number: 1
+ read_only: True
+ register: upgrade_small_part_check
+ check_mode: True
+
+- name: "Change drive letter, maximize partition size and set partition to read only"
+ win_partition:
+ drive_letter: E
+ state: present
+ partition_size: -1
+ disk_number: 1
+ partition_number: 1
+ read_only: True
+ register: upgrade_small_part
+
+- name: "Change drive letter, maximize partition size and set partition to read only (idempotence)"
+ win_partition:
+ drive_letter: E
+ state: present
+ partition_size: -1
+ disk_number: 1
+ partition_number: 1
+ read_only: True
+ register: upgrade_small_part_idempotence
+
+- ansible.windows.win_shell: $AnsiPart = Get-Partition -DriveLetter E; "$($AnsiPart.DriveLetter),$($AnsiPart.Size),$($AnsiPart.IsReadOnly)"
+ register: get_max_part
+
+- name: Check if creation and updation were successful
+ assert:
+ that:
+ - upgrade_small_part_check is changed
+ - upgrade_small_part is changed
+ - upgrade_small_part_idempotence is not changed
+ - get_max_part.stdout | trim == "E,2096037888,True"
+
+- name: "Changing size of a read only partition"
+ win_partition:
+ drive_letter: E
+ partition_size: 1 GiB
+ register: modify_read_only_partition
+ ignore_errors: True
+
+- assert:
+ that:
+ - modify_read_only_partition is failed
+
+- name: "Delete partition (check mode)"
+ win_partition:
+ disk_number: 1
+ partition_number: 1
+ state: absent
+ register: delete_partition_check
+ check_mode: True
+
+- name: "Delete partition"
+ win_partition:
+ disk_number: 1
+ partition_number: 1
+ state: absent
+ register: delete_partition
+
+- name: "Delete partition (idempotence)"
+ win_partition:
+ disk_number: 1
+ partition_number: 1
+ state: absent
+ register: delete_partition_idempotence
+
+- name: "Confirm that the partition is absent"
+ ansible.windows.win_shell: Get-Partition -DiskNumber 1 -PartitionNumber 1
+ register: confirm_partition_deletion
+ ignore_errors: True
+
+- assert:
+ that:
+ - delete_partition_check is changed
+ - delete_partition is changed
+ - delete_partition_idempotence is not changed
+ - '"No matching MSFT_Partition objects found" in confirm_partition_deletion.stderr'
+
+- name: "Create new partition without drive letter and ifs mbr type (check mode)"
+ win_partition:
+ disk_number: 1
+ partition_size: -1
+ mbr_type: ifs
+ offline: True
+ register: recreate_partition_check
+ check_mode: True
+
+- name: "Create new partition without drive letter and ifs mbr type"
+ win_partition:
+ disk_number: 1
+ partition_size: -1
+ mbr_type: ifs
+ offline: True
+ register: recreate_partition
+
+- name: "Create new partition without drive letter and ifs mbr type (idempotence failure)" # Disk is full now; no idempotence without drive letters
+ win_partition:
+ disk_number: 1
+ partition_size: -1
+ mbr_type: ifs
+ offline: True
+ register: recreate_partition_idempotence_failure
+ ignore_errors: True
+
+- name: "Confirm that new partition is created with maximum size, is offline and is IFS"
+ ansible.windows.win_shell: $AnsiPart = Get-Partition -DiskNumber 1 -PartitionNumber 1; "$($AnsiPart.Size),$($AnsiPart.IsOffline),$($AnsiPart.MbrType)"
+ register: confirm_recreate_partition
+
+- assert:
+ that:
+ - recreate_partition_check is changed
+ - recreate_partition is changed
+ - recreate_partition_idempotence_failure is failed
+ - confirm_recreate_partition.stdout | trim == "2096037888,True,7"
+
+- name: "Adding a drive letter to our partition should bring it back online (check mode)"
+ win_partition:
+ drive_letter: D
+ disk_number: 1
+ partition_number: 1
+ register: add_drive_letter_check
+ ignore_errors: True
+ check_mode: True
+
+- name: "Adding a drive letter to our partition should bring it back online"
+ win_partition:
+ drive_letter: D
+ disk_number: 1
+ partition_number: 1
+ register: add_drive_letter
+ ignore_errors: True
+
+- name: "Adding a drive letter to our partition should bring it back online (idempotence)"
+ win_partition:
+ drive_letter: D
+ disk_number: 1
+ partition_number: 1
+ register: add_drive_letter_idempotence
+ ignore_errors: True
+
+- name: "Confirm that drive is back online"
+ ansible.windows.win_shell: $AnsiPart = Get-Partition -DiskNumber 1 -PartitionNumber 1; "$($AnsiPart.DriveLetter),$($AnsiPart.IsOffline)"
+ register: confirm_add_drive_letter
+ ignore_errors: True
+
+- assert:
+ that:
+ - add_drive_letter_check is changed
+ - add_drive_letter is changed
+ - add_drive_letter_idempotence is not changed
+ - confirm_add_drive_letter.stdout | trim == "D,False"
+
+- name: "Remove partition again (check mode)"
+ win_partition:
+ drive_letter: D
+ state: absent
+ register: delete_partition_again_check
+ check_mode: True
+
+- name: "Remove partition again"
+ win_partition:
+ drive_letter: D
+ state: absent
+ register: delete_partition_again
+
+- name: "Remove partition again (idempotence)"
+ win_partition:
+ drive_letter: D
+ state: absent
+ register: delete_partition_again_idempotence
+
+- assert:
+ that:
+ - delete_partition_again_check is changed
+ - delete_partition_again is changed
+ - delete_partition_again_idempotence is not changed
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_partition/templates/vhdx_creation_script.j2 b/ansible_collections/community/windows/tests/integration/targets/win_partition/templates/vhdx_creation_script.j2
new file mode 100644
index 000000000..905373be1
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_partition/templates/vhdx_creation_script.j2
@@ -0,0 +1,7 @@
+create vdisk file="{{ AnsibleVhdx }}" maximum=2000 type=fixed
+
+select vdisk file="{{ AnsibleVhdx }}"
+
+attach vdisk
+
+convert mbr
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_partition/templates/vhdx_deletion_script.j2 b/ansible_collections/community/windows/tests/integration/targets/win_partition/templates/vhdx_deletion_script.j2
new file mode 100644
index 000000000..c2be9cd14
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_partition/templates/vhdx_deletion_script.j2
@@ -0,0 +1,3 @@
+select vdisk file="{{ AnsibleVhdx }}"
+
+detach vdisk
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_pester/aliases b/ansible_collections/community/windows/tests/integration/targets/win_pester/aliases
new file mode 100644
index 000000000..423ce3910
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_pester/aliases
@@ -0,0 +1 @@
+shippable/windows/group2
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_pester/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_pester/defaults/main.yml
new file mode 100644
index 000000000..3507a0fda
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_pester/defaults/main.yml
@@ -0,0 +1,3 @@
+---
+test_win_pester_path: C:\ansible\win_pester
+test_report_file: c:\ansible\win_pester\test_report.xml
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_pester/files/fail.ps1 b/ansible_collections/community/windows/tests/integration/targets/win_pester/files/fail.ps1
new file mode 100644
index 000000000..4bd20a601
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_pester/files/fail.ps1
@@ -0,0 +1,2 @@
+# This makes sure that a file that does not end with *.test.ps1 does not run
+throw "should never fail"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_pester/files/test01.tests.ps1 b/ansible_collections/community/windows/tests/integration/targets/win_pester/files/test01.tests.ps1
new file mode 100644
index 000000000..6248b2f77
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_pester/files/test01.tests.ps1
@@ -0,0 +1,5 @@
+Describe -Name 'Test01' {
+ It -name 'First Test' {
+ { Get-Service } | Should Not Throw
+ }
+} \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_pester/files/test02.tests.ps1 b/ansible_collections/community/windows/tests/integration/targets/win_pester/files/test02.tests.ps1
new file mode 100644
index 000000000..6d2477cc8
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_pester/files/test02.tests.ps1
@@ -0,0 +1,5 @@
+Describe -Name 'Test02' {
+ It -name 'Second Test' {
+ { Get-Service } | Should Throw
+ }
+} \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_pester/files/test03.tests.ps1 b/ansible_collections/community/windows/tests/integration/targets/win_pester/files/test03.tests.ps1
new file mode 100644
index 000000000..8dafbc6ff
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_pester/files/test03.tests.ps1
@@ -0,0 +1,11 @@
+Describe -Name 'Test03 without tag' {
+ It -name 'Third Test without tag' {
+ { Get-Service } | Should Not Throw
+ }
+}
+
+Describe -Name 'Test03 with tag' -Tag tag1 {
+ It -name 'Third Test with tag' {
+ { Get-Service } | Should Not Throw
+ }
+} \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_pester/files/test04.tests.ps1 b/ansible_collections/community/windows/tests/integration/targets/win_pester/files/test04.tests.ps1
new file mode 100644
index 000000000..07d1bd43c
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_pester/files/test04.tests.ps1
@@ -0,0 +1,18 @@
+Param(
+ $Service,
+ $Process
+)
+
+Describe "Process should exist" {
+ it "Process $Process should be running" -Skip:([String]::IsNullOrEmpty($Process)) {
+ Get-Process -Name $Process -ErrorAction SilentlyContinue | Should Not BeNullOrEmpty
+ }
+}
+
+
+
+Describe "Service should exist" -tag Service {
+ it "Service $Service should exist" -Skip:([String]::IsNullOrEmpty($Service)) {
+ Get-Service -Name $Service -ErrorAction SilentlyContinue | Should Not BeNullOrEmpty
+ }
+}
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_pester/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_pester/tasks/main.yml
new file mode 100644
index 000000000..baf6b0c50
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_pester/tasks/main.yml
@@ -0,0 +1,60 @@
+---
+- name: create test folder(s)
+ ansible.windows.win_file:
+ path: '{{test_win_pester_path}}\{{item}}'
+ state: directory
+ with_items:
+ - Modules
+ - Tests
+
+- name: download Pester module from S3 bucket
+ ansible.windows.win_get_url:
+ # this was downloaded straight off the Pester GitHub release page and uploaded to the S3 bucket
+ # https://github.com/pester/Pester/releases
+ url: 'https://ansible-ci-files.s3.amazonaws.com/test/integration/roles/test_win_pester/Pester-4.3.1.zip'
+ dest: '{{test_win_pester_path}}\Pester-4.3.1.zip'
+ register: download_res
+ until: download_res is successful
+ retries: 3
+ delay: 5
+
+- name: unzip Pester module
+ win_unzip:
+ src: '{{test_win_pester_path}}\Pester-4.3.1.zip'
+ dest: '{{test_win_pester_path}}\Modules'
+
+- name: rename extracted zip to match module name
+ ansible.windows.win_shell: Rename-Item -Path '{{test_win_pester_path}}\Modules\Pester-4.3.1' -NewName Pester
+
+- name: add custom Pester location to the PSModulePath
+ ansible.windows.win_path:
+ name: PSModulePath
+ scope: machine
+ state: present
+ elements:
+ - '{{test_win_pester_path}}\Modules'
+
+- name: copy test files
+ ansible.windows.win_copy:
+ src: files/
+ dest: '{{test_win_pester_path}}\Tests'
+
+- block:
+ - name: run Pester tests
+ include_tasks: test.yml
+ vars:
+ test_path: '{{ test_win_pester_path }}\Tests'
+
+ always:
+ - name: remove custom pester location on the PSModulePath
+ ansible.windows.win_path:
+ name: PSModulePath
+ scope: machine
+ state: absent
+ elements:
+ - '{{test_win_pester_path}}\Modules'
+
+ - name: delete test folder
+ ansible.windows.win_file:
+ path: '{{test_win_pester_path}}'
+ state: absent
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_pester/tasks/test.yml b/ansible_collections/community/windows/tests/integration/targets/win_pester/tasks/test.yml
new file mode 100644
index 000000000..cbcbd4cbe
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_pester/tasks/test.yml
@@ -0,0 +1,134 @@
+---
+- name: Run Pester test(s) specifying a fake test file
+ win_pester:
+ path: '{{test_path}}\fakefile.ps1'
+ register: fake_file
+ failed_when: '"Cannot find file or directory: ''" + test_path + "\\fakefile.ps1'' as it does not exist" not in fake_file.msg'
+
+- name: Run Pester test(s) specifying a fake folder
+ win_pester:
+ path: '{{test_path }}\fakedir'
+ register: fake_folder
+ failed_when: '"Cannot find file or directory: ''" + test_path + "\\fakedir'' as it does not exist" not in fake_folder.msg'
+
+- name: Run Pester test(s) specifying a test file and a higher pester version
+ win_pester:
+ path: '{{test_path}}\test01.tests.ps1'
+ minimum_version: '6.0.0'
+ register: invalid_version
+ failed_when: '"Pester version is not greater or equal to 6.0.0" not in invalid_version.msg'
+
+- name: Run Pester test(s) specifying a test file
+ win_pester:
+ path: '{{test_path}}\test01.tests.ps1'
+ register: file_result
+
+- name: assert Run Pester test(s) specify a test file
+ assert:
+ that:
+ - file_result.changed
+ - not file_result.failed
+ - file_result.output.TotalCount == 1
+
+- name: Run Pester test(s) specifying a test file and with a minimum mandatory Pester version
+ win_pester:
+ path: '{{test_path}}\test01.tests.ps1'
+ minimum_version: 3.0.0
+ register: file_result_with_version
+
+- name: assert Run Pester test(s) specifying a test file and a minimum mandatory Pester version
+ assert:
+ that:
+ - file_result_with_version.changed
+ - not file_result_with_version.failed
+ - file_result_with_version.output.TotalCount == 1
+
+- name: Run Pester test(s) located in a folder. Folder path end with '\'
+ win_pester:
+ path: '{{test_path}}\'
+ register: dir_with_ending_slash
+
+- name: assert Run Pester test(s) located in a folder. Folder path end with '\'
+ assert:
+ that:
+ - dir_with_ending_slash.changed
+ - not dir_with_ending_slash.failed
+ - dir_with_ending_slash.output.TotalCount == 6
+
+- name: Run Pester test(s) located in a folder. Folder path does not end with '\'
+ win_pester:
+ path: '{{test_path}}'
+ register: dir_without_ending_slash
+
+- name: assert Run Pester test(s) located in a folder. Folder does not end with '\'
+ assert:
+ that:
+ - dir_without_ending_slash.changed
+ - not dir_without_ending_slash.failed
+ - dir_without_ending_slash.output.TotalCount == 6
+
+- name: Run Pester test(s) located in a folder and with a minimum mandatory Pester version
+ win_pester:
+ path: '{{test_path}}'
+ minimum_version: 3.0.0
+ register: dir_with_version
+
+- name: assert Run Pester test(s) located in a folder and with a minimum mandatory Pester version
+ assert:
+ that:
+ - dir_with_version.changed
+ - not dir_with_version.failed
+ - dir_with_version.output.TotalCount == 6
+
+- name: Run Pester test(s) specifying a test file without specifying tag
+ win_pester:
+ path: '{{test_path}}\test03.tests.ps1'
+ register: test_no_tag
+
+- name: assert Run Pester test(s) specifying a test file and all tests executed
+ assert:
+ that:
+ - test_no_tag.changed
+ - test_no_tag.output.TotalCount == 2
+
+- name: Run Pester test(s) specifying a test file with tag
+ win_pester:
+ path: '{{test_path}}\test03.tests.ps1'
+ tags: tag1
+ register: test_with_tag
+
+- name: Run Pester test(s) specifying a test file and only test with sepecified tag executed
+ assert:
+ that:
+ - test_with_tag.changed
+ - test_with_tag.output.TotalCount == 1
+
+- name: Run Pester test(s) specifying a test file with parameters
+ win_pester:
+ path: '{{test_path}}\test04.tests.ps1'
+ test_parameters:
+ Process: lsass
+ Service: bits
+ register: test_with_parameter
+
+- name: Run Pester test(s) specifying a test file with parameters
+ assert:
+ that:
+ - test_with_parameter.changed
+ - test_with_parameter.output.PassedCount == 2
+ - test_with_parameter.output.TotalCount == 2
+
+- name: Run Pester test(s) specifying a test file by generating test result xml
+ win_pester:
+ path: '{{test_path}}\test03.tests.ps1'
+ output_file: '{{test_report_file}}'
+
+- name: Checks if the output result file exists
+ ansible.windows.win_stat:
+ path: '{{test_report_file}}'
+ register: test_output_file
+
+- name: Checks if the output result file exists
+ assert:
+ that:
+ - test_output_file.stat.exists
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_power_plan/aliases b/ansible_collections/community/windows/tests/integration/targets/win_power_plan/aliases
new file mode 100644
index 000000000..215e0b069
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_power_plan/aliases
@@ -0,0 +1 @@
+shippable/windows/group4
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_power_plan/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_power_plan/tasks/main.yml
new file mode 100644
index 000000000..cffc8447c
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_power_plan/tasks/main.yml
@@ -0,0 +1,128 @@
+# I dislike this but 2008 doesn't support the Win32_PowerPlan WMI provider
+- name: get current plan details
+ ansible.windows.win_shell: |
+ $plan_info = powercfg.exe /list
+ ($plan_info | Select-String -Pattern '\(([\w\s]*)\) \*$').Matches.Groups[1].Value
+ ($plan_info | Select-String -Pattern '\(([\w\s]*)\)$').Matches.Groups[1].Value
+ register: plan_info
+
+- set_fact:
+ original_plan: '{{ plan_info.stdout_lines[0] }}'
+ name: '{{ plan_info.stdout_lines[1] }}'
+
+- block:
+ #Test that plan detects change is needed, but doesn't actually apply change
+ - name: set power plan (check mode)
+ win_power_plan:
+ name: "{{ name }}"
+ register: set_plan_check
+ check_mode: yes
+
+ - name: get result of set power plan (check mode)
+ ansible.windows.win_shell: (powercfg.exe /list | Select-String -Pattern '\({{ name }}\)').Line
+ register: set_plan_check_result
+ changed_when: False
+
+ # verify that the powershell check is showing the plan as still inactive on the system
+ - name: assert setting plan (check mode)
+ assert:
+ that:
+ - set_plan_check is changed
+ - not set_plan_check_result.stdout_lines[0].endswith('*')
+
+ #Test that setting plan and that change is applied
+ - name: set power plan
+ win_power_plan:
+ name: "{{ name }}"
+ register: set_plan
+
+ - name: get result of set power plan
+ ansible.windows.win_shell: (powercfg.exe /list | Select-String -Pattern '\({{ name }}\)').Line
+ register: set_plan_result
+ changed_when: False
+
+ - name: assert setting plan
+ assert:
+ that:
+ - set_plan is changed
+ - set_plan_result.stdout_lines[0].endswith('*')
+
+ #Test that plan doesn't apply change if it is already set
+ - name: set power plan (idempotent)
+ win_power_plan:
+ name: "{{ name }}"
+ register: set_plan_idempotent
+
+ - name: assert setting plan (idempotent)
+ assert:
+ that:
+ - set_plan_idempotent is not changed
+
+ always:
+ - name: always change back plan to the original when done testing
+ win_power_plan:
+ name: '{{ original_plan }}'
+
+- name: get current plan guid details
+ ansible.windows.win_shell: |
+ $plan_info = powercfg.exe /list
+ ($plan_info | Select-String -Pattern '([a-z0-9]+\-[a-z0-9]+\-[a-z0-9]+\-[a-z0-9]+\-[a-z0-9]+).+\*').Matches.Groups[1].Value
+ ($plan_info | Select-String -Pattern '([a-z0-9]+\-[a-z0-9]+\-[a-z0-9]+\-[a-z0-9]+\-[a-z0-9]+)').Matches.Groups[1].Value
+ register: guid_plan_info
+
+- set_fact:
+ original_plan: '{{ guid_plan_info.stdout_lines[0] }}'
+ name: '{{ guid_plan_info.stdout_lines[1] }}'
+
+- block:
+ #Test that plan detects change is needed, but doesn't actually apply change
+ - name: set power plan guid (check mode)
+ win_power_plan:
+ guid: "{{ name }}"
+ register: set_plan_check_guid
+ check_mode: yes
+
+ - name: get result of set power plan guid (check mode)
+ ansible.windows.win_shell: (powercfg.exe /list | Select-String -Pattern '{{ name }}').Line
+ register: set_plan_check_result_guid
+ changed_when: False
+
+ # verify that the powershell check is showing the plan as still inactive on the system
+ - name: assert setting plan guid (check mode)
+ assert:
+ that:
+ - set_plan_check_guid is changed
+ - not set_plan_check_result_guid.stdout_lines[0].endswith('*')
+
+ #Test that setting plan and that change is applied
+ - name: set power plan guid
+ win_power_plan:
+ guid: "{{ name }}"
+ register: set_plan_guid
+
+ - name: get result of set power plan guid
+ ansible.windows.win_shell: (powercfg.exe /list | Select-String -Pattern '{{ name }}').Line
+ register: set_plan_result_guid
+ changed_when: False
+
+ - name: assert setting plan guid
+ assert:
+ that:
+ - set_plan_guid is changed
+ - set_plan_result_guid.stdout_lines[0].endswith('*')
+
+ #Test that plan doesn't apply change if it is already set
+ - name: set power plan guid (idempotent)
+ win_power_plan:
+ guid: "{{ name }}"
+ register: set_plan_idempotent_guid
+
+ - name: assert setting plan guid (idempotent)
+ assert:
+ that:
+ - set_plan_idempotent_guid is not changed
+
+ always:
+ - name: always change back plan to the original when done testing guid
+ win_power_plan:
+ guid: '{{ original_plan }}'
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_product_facts/aliases b/ansible_collections/community/windows/tests/integration/targets/win_product_facts/aliases
new file mode 100644
index 000000000..4cd27b3cb
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_product_facts/aliases
@@ -0,0 +1 @@
+shippable/windows/group1
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_product_facts/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_product_facts/tasks/main.yml
new file mode 100644
index 000000000..b1427eeaa
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_product_facts/tasks/main.yml
@@ -0,0 +1,11 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2017, Dag Wieers (dagwieers) <dag@wieers.com>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+- win_product_facts:
+
+- assert:
+ that:
+ - ansible_os_product_id is defined
+ - ansible_os_product_key is defined
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psexec/aliases b/ansible_collections/community/windows/tests/integration/targets/win_psexec/aliases
new file mode 100644
index 000000000..4f4664b68
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psexec/aliases
@@ -0,0 +1 @@
+shippable/windows/group5
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psexec/meta/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_psexec/meta/main.yml
new file mode 100644
index 000000000..9f37e96cd
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psexec/meta/main.yml
@@ -0,0 +1,2 @@
+dependencies:
+- setup_remote_tmp_dir
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psexec/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_psexec/tasks/main.yml
new file mode 100644
index 000000000..5f4be3ebf
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psexec/tasks/main.yml
@@ -0,0 +1,102 @@
+# Would use [] but this has troubles with PATH and trying to find the executable so just resort to keeping a space
+- name: record special path for tests
+ set_fact:
+ testing_dir: '{{ remote_tmp_dir }}\ansible win_psexec'
+
+- name: create special path testing dir
+ ansible.windows.win_file:
+ path: '{{ testing_dir }}'
+ state: directory
+
+- name: Download PsExec
+ ansible.windows.win_get_url:
+ url: https://ansible-ci-files.s3.amazonaws.com/test/integration/targets/win_psexec/PsExec.exe
+ dest: '{{ testing_dir }}\PsExec.exe'
+ register: download_res
+ until: download_res is successful
+ retries: 3
+ delay: 5
+
+- name: Get the existing PATH env var
+ ansible.windows.win_shell: '$env:PATH'
+ register: system_path
+ changed_when: False
+
+- name: Run whoami
+ win_psexec:
+ command: whoami.exe
+ nobanner: true
+ register: whoami
+ environment:
+ PATH: '{{ testing_dir }};{{ system_path.stdout | trim }}'
+
+- name: Test whoami
+ assert:
+ that:
+ - whoami.rc == 0
+ - whoami.stdout == ''
+ # FIXME: Standard output does not work or is truncated
+ #- whoami.stdout == '{{ ansible_hostname|lower }}'
+
+- name: Run whoami as SYSTEM
+ win_psexec:
+ command: whoami.exe
+ system: yes
+ nobanner: true
+ executable: '{{ testing_dir }}\PsExec.exe'
+ register: whoami_as_system
+ # Seems to be a bug with PsExec where the stdout can be empty, just retry the task to make this test a bit more stable
+ until: whoami_as_system.rc == 0 and whoami_as_system.stdout == 'nt authority\system'
+ retries: 3
+ delay: 2
+
+# FIXME: Behaviour is not consistent on all Windows systems
+#- name: Run whoami as ELEVATED
+# win_psexec:
+# command: whoami.exe
+# elevated: yes
+# register: whoami_as_elevated
+#
+## Ensure we have basic facts
+#- ansible.windows.setup:
+#
+#- debug:
+# msg: '{{ whoami_as_elevated.stdout|lower }} == {{ ansible_hostname|lower }}\{{ ansible_user_id|lower }}'
+#
+#- name: Test whoami
+# assert:
+# that:
+# - whoami_as_elevated.rc == 0
+# - whoami_as_elevated.stdout|lower == '{{ ansible_hostname|lower }}\{{ ansible_user_id|lower }}'
+
+- name: Run command with multiple arguments
+ win_psexec:
+ command: powershell.exe -NonInteractive "exit 1"
+ ignore_errors: yes
+ register: whoami_multiple_args
+ environment:
+ PATH: '{{ testing_dir }};{{ system_path.stdout | trim }}'
+
+- name: Test command with multiple argumetns
+ assert:
+ that:
+ - whoami_multiple_args.rc == 1
+ - whoami_multiple_args.psexec_command == "psexec.exe -accepteula powershell.exe -NonInteractive \"exit 1\""
+
+- name: Run command with password
+ win_psexec:
+ command: whoami.exe
+ username: fake_user
+ password: '{{ item }}'
+ executable: '{{ testing_dir }}\PsExec.exe'
+ ignore_errors: yes # The username/password isn't valid so it will fail
+ loop:
+ - Testing123
+ - Testing"123 # This makes sure the escaped password for the cmd is also masked
+ register: psexec_pass
+
+- name: Test password not in psexec_command output
+ assert:
+ that:
+ - psexec_pass.results[0].psexec_command.endswith("-u fake_user -p *PASSWORD_REPLACED* -accepteula whoami.exe")
+ - psexec_pass.results[1].psexec_command.endswith("-u fake_user -p *PASSWORD_REPLACED* -accepteula whoami.exe")
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psmodule/aliases b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/aliases
new file mode 100644
index 000000000..4cd27b3cb
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/aliases
@@ -0,0 +1 @@
+shippable/windows/group1
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/module/license.txt b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/module/license.txt
new file mode 100644
index 000000000..81f2d4566
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/module/license.txt
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 Ansible
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/module/template.nuspec b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/module/template.nuspec
new file mode 100644
index 000000000..cb52fb42d
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/module/template.nuspec
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
+ <metadata>
+ <id>--- NAME ---</id>
+ <version>--- VERSION ---</version>
+ <authors>Ansible</authors>
+ <owners>Ansible</owners>
+ <requireLicenseAcceptance>--- LICACC ---</requireLicenseAcceptance>
+ <licenseUrl>https://choosealicense.com/licenses/mit/</licenseUrl>
+ <description>Test for Ansible win_ps* modules</description>
+ <releaseNotes></releaseNotes>
+ <copyright>Copyright (c) 2019 Ansible, licensed under MIT.</copyright>
+ <tags>PowerShellGetFormatVersion_2.0 PSModule PSIncludes_Function PSFunction_--- FUNCTION --- PSCommand_--- FUNCTION ---</tags>
+ </metadata>
+</package>
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/module/template.psd1 b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/module/template.psd1
new file mode 100644
index 000000000..cd6709722
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/module/template.psd1
@@ -0,0 +1,17 @@
+@{
+ RootModule = '--- NAME ---.psm1'
+ ModuleVersion = '--- VERSION ---'
+ GUID = '--- GUID ---'
+ Author = 'Ansible'
+ Copyright = 'Copyright (c) 2019 Ansible, licensed under MIT.'
+ Description = "Test for Ansible win_ps* modules"
+ PowerShellVersion = '3.0'
+ FunctionsToExport = @(
+ "--- FUNCTION ---"
+ )
+ PrivateData = @{
+ PSData = @{
+--- PS_DATA ---
+ }
+ }
+}
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/module/template.psm1 b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/module/template.psm1
new file mode 100644
index 000000000..ac38fb5ed
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/module/template.psm1
@@ -0,0 +1,10 @@
+Function --- FUNCTION --- {
+ return [PSCustomObject]@{
+ Name = "--- NAME ---"
+ Version = "--- VERSION ---"
+ Repo = "--- REPO ---"
+ }
+}
+
+Export-ModuleMember -Function --- FUNCTION ---
+
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/openssl.conf b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/openssl.conf
new file mode 100644
index 000000000..2b5685b43
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/openssl.conf
@@ -0,0 +1,9 @@
+distinguished_name = req_distinguished_name
+
+[req_distinguished_name]
+
+[req_sign]
+subjectKeyIdentifier=hash
+basicConstraints = CA:FALSE
+keyUsage = digitalSignature
+extendedKeyUsage = codeSigning
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/setup_certs.sh b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/setup_certs.sh
new file mode 100644
index 000000000..258567316
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/setup_certs.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+
+# Generate key used for CA cert
+openssl genrsa -aes256 -out ca.key -passout pass:password 2048
+
+# Generate CA certificate
+openssl req -new -x509 -days 365 -key ca.key -out ca.pem -subj "/CN=Ansible Root" -passin pass:password
+
+# Generate key used for signing cert
+openssl genrsa -aes256 -out sign.key -passout pass:password 2048
+
+# Generate CSR for signing cert that includes CodeSiging extension
+openssl req -new -key sign.key -out sign.csr -subj "/CN=Ansible Sign" -config openssl.conf -reqexts req_sign -passin pass:password
+
+# Generate signing certificate
+openssl x509 -req -in sign.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out sign.pem -days 365 -extfile openssl.conf -extensions req_sign -passin pass:password
+
+# Create pfx that includes signing cert and cert with the pass 'password'
+openssl pkcs12 -export -out sign.pfx -inkey sign.key -in sign.pem -passin pass:password -passout pass:password
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/setup_modules.ps1 b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/setup_modules.ps1
new file mode 100644
index 000000000..48d55b574
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/setup_modules.ps1
@@ -0,0 +1,89 @@
+$ErrorActionPreference = "Stop"
+
+$template_path = $args[0]
+$template_manifest = Join-Path -Path $template_path -ChildPath template.psd1
+$template_script = Join-Path -Path $template_path -ChildPath template.psm1
+$template_nuspec = Join-Path -Path $template_path -ChildPath template.nuspec
+$template_license = Join-Path -Path $template_path -ChildPath license.txt
+$nuget_exe = Join-Path -Path $template_path -ChildPath nuget.exe
+$sign_cert = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList @(
+ (Join-Path -Path $template_path -ChildPath sign.pfx),
+ 'password',
+ # We need to use MachineKeySet so we can load the pfx without using become
+ # EphemeralKeySet would be better but it is only available starting with .NET 4.7.2
+ [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::MachineKeySet
+)
+
+$packages = @(
+ @{ name = "ansible-test1"; version = "1.0.0"; repo = "PSRepo 1"; function = "Get-AnsibleTest1" }
+ @{ name = "ansible-test1"; version = "1.0.5"; repo = "PSRepo 1"; function = "Get-AnsibleTest1" }
+ @{ name = "ansible-test1"; version = "1.1.0"; repo = "PSRepo 1"; function = "Get-AnsibleTest1" }
+ @{ name = "ansible-test2"; version = "1.0.0"; repo = "PSRepo 1"; function = "Get-AnsibleTest2" }
+ @{ name = "ansible-test2"; version = "1.0.0"; repo = "PSRepo 2"; function = "Get-AnsibleTest2" }
+ @{ name = "ansible-test2"; version = "1.0.1"; repo = "PSRepo 1"; function = "Get-AnsibleTest2"; signed = $false }
+ @{ name = "ansible-test2"; version = "1.1.0"; prerelease = "beta1"; repo = "PSRepo 1"; function = "Get-AnsibleTest2" }
+ @{ name = "ansible-clobber"; version = "0.1.0"; repo = "PSRepo 1"; function = "Enable-PSTrace" }
+ @{ name = "ansible-licensed" ; version = "1.1.1"; repo = "PSRepo 1" ; require_license = $true; function = "Get-AnsibleLicensed" }
+)
+
+foreach ($package in $packages) {
+ $tmp_dir = Join-Path -Path $template_path -ChildPath $package.name
+ if (Test-Path -Path $tmp_dir) {
+ Remove-Item -Path $tmp_dir -Force -Recurse
+ }
+ New-Item -Path $tmp_dir -ItemType Directory > $null
+
+ Copy-Item -LiteralPath $template_license -Destination $tmp_dir -Force
+
+ try {
+ $ps_data = @("LicenseUri = 'https://choosealicense.com/licenses/mit/'")
+ $nuget_version = $package.version
+ if ($package.ContainsKey("prerelease")) {
+ $ps_data += "Prerelease = '$($package.prerelease)'"
+ $nuget_version = "$($package.version)-$($package.prerelease)"
+ }
+ if ($package.ContainsKey("require_license")) {
+ $ps_data += "RequireLicenseAcceptance = `$$($package.require_license)"
+ }
+
+ $manifest = [System.IO.File]::ReadAllText($template_manifest)
+ $manifest = $manifest.Replace('--- NAME ---', $package.name).Replace('--- VERSION ---', $package.version)
+ $manifest = $manifest.Replace('--- GUID ---', [Guid]::NewGuid()).Replace('--- FUNCTION ---', $package.function)
+
+ $manifest = $manifest.Replace('--- PS_DATA ---', $ps_data -join "`n")
+ $manifest_path = Join-Path -Path $tmp_dir -ChildPath "$($package.name).psd1"
+ Set-Content -Path $manifest_path -Value $manifest
+
+ $script = [System.IO.File]::ReadAllText($template_script)
+ $script = $script.Replace('--- NAME ---', $package.name).Replace('--- VERSION ---', $package.version)
+ $script = $script.Replace('--- REPO ---', $package.repo).Replace('--- FUNCTION ---', $package.function)
+ $script_path = Join-Path -Path $tmp_dir -ChildPath "$($package.name).psm1"
+ Set-Content -Path $script_path -Value $script
+
+ $signed = if ($package.ContainsKey("signed")) { $package.signed } else { $true }
+ if ($signed) {
+ Set-AuthenticodeSignature -Certificate $sign_cert -LiteralPath $manifest_path > $null
+ Set-AuthenticodeSignature -Certificate $sign_cert -LiteralPath $script_path > $null
+ }
+
+ # We should just be able to use Publish-Module but it fails when running over WinRM for older hosts and become
+ # does not fix this. It fails to respond to nuget.exe push errors when it canno find the .nupkg file. We will
+ # just manually do that ourselves. This also has the added benefit of being a lot quicker than Publish-Module
+ # which seems to take forever to publish the module.
+ $nuspec = [System.IO.File]::ReadAllText($template_nuspec)
+ $nuspec = $nuspec.Replace('--- NAME ---', $package.name).Replace('--- VERSION ---', $nuget_version)
+ $nuspec = $nuspec.Replace('--- FUNCTION ---', $package.function)
+ $nuspec = $nuspec.Replace('--- LICACC ---', ($package.require_license -as [bool]).ToString().ToLower())
+ Set-Content -Path (Join-Path -Path $tmp_dir -ChildPath "$($package.name).nuspec") -Value $nuspec
+
+ &$nuget_exe pack "$tmp_dir\$($package.name).nuspec" -outputdirectory $tmp_dir
+
+ $repo_path = Join-Path -Path $template_path -ChildPath $package.repo
+ $nupkg_filename = "$($package.name).$($nuget_version).nupkg"
+ Copy-Item -Path (Join-Path -Path $tmp_dir -ChildPath $nupkg_filename) `
+ -Destination (Join-Path -Path $repo_path -ChildPath $nupkg_filename)
+ }
+ finally {
+ Remove-Item -Path $tmp_dir -Force -Recurse
+ }
+}
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psmodule/handlers/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/handlers/main.yml
new file mode 100644
index 000000000..13797f236
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/handlers/main.yml
@@ -0,0 +1,34 @@
+---
+- name: re-add PSGallery repository
+ ansible.windows.win_shell: Register-PSRepository -Default -InstallationPolicy Untrusted
+
+- name: remove registered repos
+ win_psrepository:
+ name: '{{ item }}'
+ state: absent
+ loop:
+ - PSRepo 1
+ - PSRepo 2
+
+- name: remove CA cert from trusted root store
+ ansible.windows.win_certificate_store:
+ thumbprint: '{{ ca_cert_import.thumbprints[0] }}'
+ store_location: LocalMachine
+ store_name: Root
+ state: absent
+
+- name: remove signing key from trusted publisher store
+ ansible.windows.win_certificate_store:
+ thumbprint: '{{ sign_cert_import.thumbprints[0] }}'
+ store_location: LocalMachine
+ store_name: TrustedPublisher
+ state: absent
+
+- name: remove test packages
+ win_psmodule:
+ name: '{{ item }}'
+ state: absent
+ loop:
+ - ansible-test1
+ - ansible-test2
+ - ansible-clobber \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psmodule/meta/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/meta/main.yml
new file mode 100644
index 000000000..f0920878a
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/meta/main.yml
@@ -0,0 +1,3 @@
+dependencies:
+- setup_remote_tmp_dir
+- setup_win_psget
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psmodule/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/tasks/main.yml
new file mode 100644
index 000000000..ffe1a0978
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/tasks/main.yml
@@ -0,0 +1,513 @@
+# test code for the win_psmodule module when using winrm connection
+# Copyright: (c) 2018, Wojciech Sciesinski <wojciech[at]sciesinski[dot]net>
+# Copyright: (c) 2017, Daniele Lazzari <lazzari@mailup.com>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: setup test repos and modules
+ import_tasks: setup.yml
+
+# Remove the below task in Ansible 2.12
+- name: ensure warning is fired when adding a repo
+ win_psmodule:
+ name: ansible-test1
+ repository: some repo
+ url: '{{ remote_tmp_dir }}'
+ state: present
+ register: dep_repo_add
+ ignore_errors: yes # will fail because this repo doesn't actually have this module
+ check_mode: yes
+
+- name: assert warning is fired when adding a repo
+ assert:
+ that:
+ - dep_repo_add is changed
+ - dep_repo_add.deprecations|length == 1
+ - dep_repo_add.deprecations[0].msg == 'Adding a repo with this module is deprecated, the repository parameter should only be used to select a repo. Use community.windows.win_psrepository to manage repos'
+ - dep_repo_add.deprecations[0].date == '2021-07-01'
+
+### licensed module checks
+# it is not known in check mode that a module requires
+# license acceptance, so we don't do check mode tests
+# for that scenario
+
+- name: install module requiring license acceptance (no param)
+ win_psmodule:
+ name: ansible-licensed
+ state: present
+ register: install_licensed
+ ignore_errors: yes
+
+- name: get result of install package
+ ansible.windows.win_shell: (Get-Module -ListAvailable -Name ansible-licensed | Measure-Object).Count
+ register: install_actual_check
+
+- name: assert install package (failure)
+ assert:
+ that:
+ - install_licensed is failed
+ - '"License Acceptance is required for module" in install_licensed.msg'
+ - install_actual_check.stdout | trim | int == 0
+
+- name: install module requiring license acceptance
+ win_psmodule:
+ name: ansible-licensed
+ state: present
+ accept_license: true
+ register: install_licensed
+
+- name: get result of install package
+ ansible.windows.win_shell: Import-Module -Name ansible-licensed; Get-AnsibleLicensed | ConvertTo-Json
+ register: install_actual
+
+- name: assert install package
+ assert:
+ that:
+ - install_licensed is changed
+ - install_actual.stdout | from_json == {"Name":"ansible-licensed","Version":"1.1.1","Repo":"PSRepo 1"}
+
+- name: install module requiring license acceptance (idempotence)
+ win_psmodule:
+ name: ansible-licensed
+ state: present
+ accept_license: true
+ register: install_licensed
+
+- name: get result of install package (idempotence)
+ ansible.windows.win_shell: Import-Module -Name ansible-licensed; Get-AnsibleLicensed | ConvertTo-Json
+ register: install_actual
+
+- name: assert install package (idempotence)
+ assert:
+ that:
+ - install_licensed is not changed
+ - install_actual.stdout | from_json == {"Name":"ansible-licensed","Version":"1.1.1","Repo":"PSRepo 1"}
+
+### end licensed module checks
+
+- name: install package (check mode)
+ win_psmodule:
+ name: ansible-test1
+ state: present
+ register: install_check
+ check_mode: yes
+
+- name: get result of install package (check mode)
+ ansible.windows.win_shell: (Get-Module -ListAvailable -Name ansible-test1 | Measure-Object).Count
+ register: install_actual_check
+
+- name: assert install package (check mode)
+ assert:
+ that:
+ - install_check is changed
+ - install_actual_check.stdout | trim | int == 0
+
+- name: install package
+ win_psmodule:
+ name: ansible-test1
+ state: present
+ register: install
+
+- name: get result of install package
+ ansible.windows.win_shell: Import-Module -Name ansible-test1; Get-AnsibleTest1 | ConvertTo-Json
+ register: install_actual
+
+- name: assert install package
+ assert:
+ that:
+ - install is changed
+ - install_actual.stdout | from_json == {"Name":"ansible-test1","Version":"1.1.0","Repo":"PSRepo 1"}
+
+- name: install package (idempotent)
+ win_psmodule:
+ name: ansible-test1
+ state: present
+ register: install_again
+
+- name: assert install package (idempotent)
+ assert:
+ that:
+ - not install_again is changed
+
+- name: remove package (check mode)
+ win_psmodule:
+ name: ansible-test1
+ state: absent
+ register: remove_check
+ check_mode: yes
+
+- name: get result of remove package (check mode)
+ ansible.windows.win_shell: (Get-Module -ListAvailable -Name ansible-test1 | Measure-Object).Count
+ register: remove_actual_check
+
+- name: remove package (check mode)
+ assert:
+ that:
+ - remove_check is changed
+ - remove_actual_check.stdout | trim | int == 1
+
+- name: remove package
+ win_psmodule:
+ name: ansible-test1
+ state: absent
+ register: remove
+
+- name: get result of remove package
+ ansible.windows.win_shell: (Get-Module -ListAvailable -Name ansible-test1 | Measure-Object).Count
+ register: remove_actual
+
+- name: assert remove package
+ assert:
+ that:
+ - remove is changed
+ - remove_actual.stdout | trim | int == 0
+
+- name: remove package (idempotent)
+ win_psmodule:
+ name: ansible-test1
+ state: absent
+ register: remove_again
+
+- name: assert remove package (idempotent)
+ assert:
+ that:
+ - not remove_again is changed
+
+- name: fail to install module that exists in multiple repos
+ win_psmodule:
+ name: ansible-test2
+ state: present
+ register: fail_multiple_pkg
+ failed_when: 'fail_multiple_pkg.msg != "Problems installing ansible-test2 module: Unable to install, multiple modules matched ''ansible-test2''. Please specify a single -Repository."'
+
+- name: install module with specific repository
+ win_psmodule:
+ name: ansible-test2
+ repository: PSRepo 2
+ state: present
+ register: install_repo
+
+- name: get result of install module with specific repository
+ ansible.windows.win_shell: Import-Module -Name ansible-test2; Get-AnsibleTest2 | ConvertTo-Json
+ register: install_repo_actual
+
+- name: assert install module with specific repository
+ assert:
+ that:
+ - install_repo is changed
+ - install_repo_actual.stdout | from_json == {"Name":"ansible-test2","Version":"1.0.0","Repo":"PSRepo 2"}
+
+- name: install module with specific repository (idempotent)
+ win_psmodule:
+ name: ansible-test2
+ repository: PSRepo 2
+ state: present
+ register: install_repo_again
+
+- name: assert install module with specific repository (idempotent)
+ assert:
+ that:
+ - not install_repo_again is changed
+
+- name: remove package that was installed from specific repository
+ win_psmodule:
+ name: ansible-test2
+ state: absent
+ register: remove_repo_without_source
+
+- name: get result of remove package that was installed from specific repository
+ ansible.windows.win_shell: (Get-Module -ListAvailable -Name ansible-test2 | Measure-Object).Count
+ register: remove_repo_without_source_actual
+
+- name: assert remove package that was installed from specific repository
+ assert:
+ that:
+ - remove_repo_without_source is changed
+ - remove_repo_without_source_actual.stdout | trim | int == 0
+
+- name: fail to install required version that is missing
+ win_psmodule:
+ name: ansible-test1
+ required_version: 0.9.0
+ state: present
+ register: fail_missing_req
+ failed_when: '"Problems installing ansible-test1 module: No match was found for the specified search criteria" not in fail_missing_req.msg'
+
+- name: install required version
+ win_psmodule:
+ name: ansible-test1
+ required_version: 1.0.0
+ state: present
+ register: install_req_version
+
+- name: get result of install required version
+ ansible.windows.win_shell: Import-Module -Name ansible-test1; Get-AnsibleTest1 | ConvertTo-Json
+ register: install_req_version_actual
+
+- name: assert install required version
+ assert:
+ that:
+ - install_req_version is changed
+ - install_req_version_actual.stdout | from_json == {"Name":"ansible-test1","Version":"1.0.0","Repo":"PSRepo 1"}
+
+- name: install required version (idempotent)
+ win_psmodule:
+ name: ansible-test1
+ required_version: 1.0.0
+ state: present
+ register: install_req_version_again
+
+- name: assert install required version (idempotent)
+ assert:
+ that:
+ - not install_req_version_again is changed
+
+- name: remove required version
+ win_psmodule:
+ name: ansible-test1
+ required_version: 1.0.0
+ state: absent
+ register: remove_req_version
+
+- name: get result of remove required version
+ ansible.windows.win_shell: (Get-Module -ListAvailable -Name ansible-test1 | Measure-Object).Count
+ register: remove_req_version_actual
+
+- name: assert remove required version
+ assert:
+ that:
+ - remove_req_version is changed
+ - remove_req_version_actual.stdout | trim | int == 0
+
+- name: remove required version (idempotent)
+ win_psmodule:
+ name: ansible-test1
+ required_version: 1.0.0
+ state: absent
+ register: remove_req_version_again
+
+- name: assert remove required version (idempotent)
+ assert:
+ that:
+ - not remove_req_version_again is changed
+
+- name: install min max version
+ win_psmodule:
+ name: ansible-test1
+ minimum_version: 1.0.1
+ maximum_version: 1.0.9
+ state: present
+ register: install_min_max
+
+- name: get result of install min max version
+ ansible.windows.win_shell: Import-Module -Name ansible-test1; Get-AnsibleTest1 | ConvertTo-Json
+ register: install_min_max_actual
+
+- name: assert install min max version
+ assert:
+ that:
+ - install_min_max is changed
+ - install_min_max_actual.stdout | from_json == {"Name":"ansible-test1","Version":"1.0.5","Repo":"PSRepo 1"}
+
+- name: install min max version (idempotent)
+ win_psmodule:
+ name: ansible-test1
+ minimum_version: 1.0.1
+ maximum_version: 1.0.9
+ state: present
+ register: install_min_max_again
+
+- name: assert install min max version (idempotent)
+ assert:
+ that:
+ - not install_min_max_again is changed
+
+- name: update package to latest version
+ win_psmodule:
+ name: ansible-test1
+ state: latest
+ register: update_module
+
+- name: get result of update package to latest version
+ ansible.windows.win_shell: Import-Module -Name ansible-test1; Get-AnsibleTest1 | ConvertTo-Json
+ register: update_module_actual
+
+- name: assert update package to latest version
+ assert:
+ that:
+ - update_module is changed
+ - update_module_actual.stdout | from_json == {"Name":"ansible-test1","Version":"1.1.0","Repo":"PSRepo 1"}
+
+- name: update package to latest version (idempotent)
+ win_psmodule:
+ name: ansible-test1
+ state: latest
+ register: update_module_again
+
+- name: assert update package to latest version (idempotent)
+ assert:
+ that:
+ - not update_module_again is changed
+
+- name: remove package that does not match min version
+ win_psmodule:
+ name: ansible-test1
+ minimum_version: 2.0.0
+ state: absent
+ register: remove_min_no_change
+
+- name: assert remove package that does not match min version
+ assert:
+ that:
+ - not remove_min_no_change is changed
+
+- name: remove package that does not match max version
+ win_psmodule:
+ name: ansible-test1
+ maximum_version: 0.9.0
+ state: absent
+ register: remove_max_no_change
+
+- name: assert remove package that does not match max version
+ assert:
+ that:
+ - not remove_max_no_change is changed
+
+- name: uninstall package to clear tests
+ win_psmodule:
+ name: ansible-test1
+ state: absent
+
+- name: install package with max version
+ win_psmodule:
+ name: ansible-test2
+ maximum_version: 1.0.0
+ repository: PSRepo 1
+ state: present
+ register: install_max
+
+- name: get result of install package with max version
+ ansible.windows.win_shell: Import-Module -Name ansible-test2; Get-AnsibleTest2 | ConvertTo-Json
+ register: install_max_actual
+
+- name: assert install package with max version
+ assert:
+ that:
+ - install_max is changed
+ - install_max_actual.stdout | from_json == {"Name":"ansible-test2","Version":"1.0.0","Repo":"PSRepo 1"}
+
+- name: fail to install updated package without skip publisher
+ win_psmodule:
+ name: ansible-test2
+ required_version: 1.0.1 # This version has been pureposefully not been signed for testing
+ repository: PSRepo 1
+ state: present
+ register: fail_skip_pub
+ failed_when: '"The version ''1.0.1'' of the module ''ansible-test2'' being installed is not catalog signed" not in fail_skip_pub.msg'
+
+- name: install updated package provider with skip publisher
+ win_psmodule:
+ name: ansible-test2
+ required_version: 1.0.1
+ repository: PSRepo 1
+ state: present
+ skip_publisher_check: yes
+ register: install_skip_pub
+
+- name: get result of install updated package provider with skip publisher
+ ansible.windows.win_shell: Import-Module -Name ansible-test2; Get-AnsibleTest2 | ConvertTo-Json
+ register: install_skip_pub_actual
+
+- name: assert install updated package provider with skip publisher
+ assert:
+ that:
+ - install_skip_pub is changed
+ - install_skip_pub_actual.stdout | from_json == {"Name":"ansible-test2","Version":"1.0.1","Repo":"PSRepo 1"}
+
+- name: remove test package 2 for clean test
+ win_psmodule:
+ name: ansible-test2
+ state: absent
+
+- name: fail to install clobbered module
+ win_psmodule:
+ name: ansible-clobber
+ state: present
+ register: fail_clobbering_time
+ failed_when: '"If you still want to install this module ''ansible-clobber'', use -AllowClobber parameter." not in fail_clobbering_time.msg'
+
+- name: install clobbered module
+ win_psmodule:
+ name: ansible-clobber
+ allow_clobber: yes
+ state: present
+ register: install_clobber
+
+- name: get result of install clobbered module
+ ansible.windows.win_shell: Import-Module -Name ansible-clobber; Enable-PSTrace | ConvertTo-Json
+ register: install_clobber_actual
+
+- name: assert install clobbered module
+ assert:
+ that:
+ - install_clobber is changed
+ - install_clobber_actual.stdout | from_json == {"Name":"ansible-clobber","Version":"0.1.0","Repo":"PSRepo 1"}
+
+- name: remove clobbered module
+ win_psmodule:
+ name: ansible-clobber
+ state: absent
+ register: remove_clobber
+
+- name: get result of remove clobbered module
+ ansible.windows.win_shell: (Get-Module -ListAvailable -Name ansible-clobber | Measure-Object).Count
+ register: remove_clobber_actual
+
+- name: assert remove clobbered module
+ assert:
+ that:
+ - remove_clobber is changed
+ - remove_clobber_actual.stdout | trim | int == 0
+
+- name: fail to install prerelese module
+ win_psmodule:
+ name: ansible-test2
+ repository: PSRepo 1
+ required_version: 1.1.0-beta1
+ state: present
+ register: fail_install_prerelease
+ failed_when: '"The ''-AllowPrerelease'' parameter must be specified when using the Prerelease string" not in fail_install_prerelease.msg'
+
+- name: install prerelease module
+ win_psmodule:
+ name: ansible-test2
+ repository: PSRepo 1
+ required_version: 1.1.0-beta1
+ allow_prerelease: yes
+ state: present
+ register: install_prerelease
+
+- name: get result of install prerelease module
+ ansible.windows.win_shell: Import-Module -Name ansible-test2; Get-AnsibleTest2 | ConvertTo-Json
+ register: install_prerelease_actual
+
+- name: assert install prerelease module
+ assert:
+ that:
+ - install_prerelease is changed
+ - install_prerelease_actual.stdout | from_json == {"Name":"ansible-test2","Version":"1.1.0","Repo":"PSRepo 1"}
+
+- name: remove prerelease module
+ win_psmodule:
+ name: ansible-test2
+ state: absent
+ register: remove_prerelease
+
+- name: get result of remove prerelease module
+ ansible.windows.win_shell: (Get-Module -ListAvailable -Name ansible-test2 | Measure-Object).Count
+ register: remove_prerelease_actual
+
+- name: assert remove prerelease module
+ assert:
+ that:
+ - remove_prerelease is changed
+ - remove_prerelease_actual.stdout | trim | int == 0
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psmodule/tasks/setup.yml b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/tasks/setup.yml
new file mode 100644
index 000000000..42049a3e3
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/tasks/setup.yml
@@ -0,0 +1,119 @@
+# Sets up 2 local repos that contains mock packages for testing.
+#
+# PSRepo 1 contains
+# ansible-test1 - 1.0.0
+# ansible-test1 - 1.0.5
+# ansible-test1 - 1.1.0
+# ansible-test2 - 1.0.0
+# ansible-test2 - 1.0.1 (Not signed for skip_publisher tests)
+# ansible-test2 - 1.1.0-beta1
+# ansible-clobber - 0.1.0
+# ansible-licensed - 1.1.1 (requires license acceptance)
+# PSRepo 2 contains
+# ansible-test2 - 1.0.0
+#
+# These modules will have the following cmdlets
+# ansible-test1
+# Get-AnsibleTest1
+#
+# ansible-test2
+# Get-AnsibleTest2
+#
+# ansible-clobber
+# Enable-PSTrace (clobbers the Enable-PSTrace cmdlet)
+#
+# All cmdlets return
+# [PSCustomObject]@{
+# Name = "the name of the module"
+# Version = "the version of the module"
+# Repo = "the repo where the module was sourced from"
+# }
+---
+- name: create test repo folders
+ ansible.windows.win_file:
+ path: '{{ remote_tmp_dir }}\{{ item }}'
+ state: directory
+ loop:
+ - PSRepo 1
+ - PSRepo 2
+
+- name: register test repos
+ win_psrepository:
+ name: '{{ item.name }}'
+ source: '{{ remote_tmp_dir }}\{{ item.name }}'
+ installation_policy: '{{ item.policy }}'
+ notify: remove registered repos
+ loop:
+ - name: PSRepo 1
+ policy: trusted
+ - name: PSRepo 2
+ policy: untrusted
+
+- name: remove PSGallery repository
+ win_psrepository:
+ name: PSGallery
+ state: absent
+ notify: re-add PSGallery repository
+
+- name: create custom openssl conf
+ copy:
+ src: openssl.conf
+ dest: '{{ output_dir }}/openssl.conf'
+ delegate_to: localhost
+
+- name: get absolute path of output_dir for script
+ shell: echo {{ output_dir }}
+ delegate_to: localhost
+ register: output_dir_abs
+
+- name: create certificates for code signing
+ script: setup_certs.sh
+ args:
+ chdir: '{{ output_dir_abs.stdout }}'
+ delegate_to: localhost
+
+- name: copy the CA and sign certificates
+ ansible.windows.win_copy:
+ src: '{{ output_dir }}/{{ item }}'
+ dest: '{{ remote_tmp_dir }}\'
+ loop:
+ - ca.pem
+ - sign.pem
+ - sign.pfx
+
+- name: import the CA key to the trusted root store
+ ansible.windows.win_certificate_store:
+ path: '{{ remote_tmp_dir }}\ca.pem'
+ state: present
+ store_location: LocalMachine
+ store_name: Root
+ register: ca_cert_import
+ notify: remove CA cert from trusted root store
+
+- name: import the sign key to the trusted publisher store
+ ansible.windows.win_certificate_store:
+ path: '{{ remote_tmp_dir }}\sign.pem'
+ state: present
+ store_location: LocalMachine
+ store_name: TrustedPublisher
+ register: sign_cert_import
+ notify: remove signing key from trusted publisher store
+
+- name: copy across module template files
+ ansible.windows.win_copy:
+ src: module/
+ dest: '{{ remote_tmp_dir }}'
+
+# Used in the script below to create the .nupkg for each test module
+- name: download NuGet binary for module publishing
+ ansible.windows.win_get_url:
+ url: https://ansible-ci-files.s3.amazonaws.com/test/integration/targets/win_psmodule/nuget.exe
+ dest: '{{ remote_tmp_dir }}'
+ register: download_res
+ until: download_res is successful
+ retries: 3
+ delay: 5
+
+- name: create test PowerShell modules
+ script: setup_modules.ps1 "{{ remote_tmp_dir }}"
+ notify: remove test packages
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/aliases b/ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/aliases
new file mode 100644
index 000000000..423ce3910
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/aliases
@@ -0,0 +1 @@
+shippable/windows/group2
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/defaults/main.yml
new file mode 100644
index 000000000..9c9c9c078
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/defaults/main.yml
@@ -0,0 +1,70 @@
+---
+run_check_mode: False
+suffix: "{{ '(check mode)' if run_check_mode else '' }}"
+repository_name: Repo
+repo_path: "{{ remote_tmp_dir }}\\repo\\"
+
+modules_to_install:
+ - AnsibleVault
+ - PSCSharpInvoker
+ - PInvokeHelper
+
+builtin_modules:
+ - Microsoft.PowerShell.Utility
+ - Microsoft.PowerShell.Host
+ - Microsoft.PowerShell.Management
+
+sample_modules: "{{ builtin_modules + modules_to_install }}"
+
+expected_fields:
+ - prefix
+ - private_data
+ - scripts
+ - author
+ - description
+ - exported_type_files
+ - exported_workflows
+ - nested_modules
+ - exported_dsc_resources
+ - updated_date
+ - root_module
+ - power_shell_host_name
+ - module_base
+ - path
+ - exported_format_files
+ - dependencies
+ - release_notes
+ - installed_date
+ - exported_variables
+ - published_date
+ - required_assemblies
+ - version
+ - icon_uri
+ - project_uri
+ - dot_net_framework_version
+ - processor_architecture
+ - license_uri
+ - required_modules
+ - module_type
+ - compatible_ps_editions
+ - company_name
+ - copyright
+ - tags
+ - access_mode
+ - package_management_provider
+ - exported_aliases
+ - power_shell_host_version
+ - clr_version
+ - file_list
+ - help_info_uri
+ - module_list
+ - exported_functions
+ - power_shell_version
+ - guid
+ - repository_source_location
+ - exported_cmdlets
+ - exported_commands
+ - repository
+ - installed_location
+ - name
+ - log_pipeline_execution_details
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/files/ansiblevault.0.3.0.nupkg b/ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/files/ansiblevault.0.3.0.nupkg
new file mode 100644
index 000000000..52fe289ed
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/files/ansiblevault.0.3.0.nupkg
Binary files differ
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/files/pinvokehelper.0.1.0.nupkg b/ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/files/pinvokehelper.0.1.0.nupkg
new file mode 100644
index 000000000..05d30e55c
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/files/pinvokehelper.0.1.0.nupkg
Binary files differ
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/files/pscsharpinvoker.0.1.0.nupkg b/ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/files/pscsharpinvoker.0.1.0.nupkg
new file mode 100644
index 000000000..77bd15f0e
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/files/pscsharpinvoker.0.1.0.nupkg
Binary files differ
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/meta/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/meta/main.yml
new file mode 100644
index 000000000..acc7fbcae
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/meta/main.yml
@@ -0,0 +1,3 @@
+dependencies:
+ - setup_remote_tmp_dir
+ - setup_win_psget
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/tasks/common.yml b/ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/tasks/common.yml
new file mode 100644
index 000000000..290f9efbd
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/tasks/common.yml
@@ -0,0 +1,37 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2020, Brian Scholer <@briantist>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: Assert that the correct structure is returned {{ suffix }}
+ assert:
+ that:
+ - module_info.modules is defined
+ - module_info.modules is sequence()
+ quiet: yes
+
+- name: Assert that the correct number of modules are returned {{ suffix }}
+ assert:
+ that: module_info.modules | length >= expected_modules | length
+ fail_msg: >-
+ Expected {{ expected_modules | length }} modules, got {{ module_info.modules | map(attribute='name') | join(',') }} ({{ module_info.modules | length}})
+ quiet: yes
+
+- name: Assert that all expected modules are present {{ suffix }}
+ assert:
+ that: item in (module_info.modules | map(attribute='name'))
+ fail_msg: "Expected module '{{ item }}' not found in results."
+ quiet: yes
+ loop: "{{ expected_modules }}"
+ loop_control:
+ label: "Assert '{{ item }}' in result."
+
+- include_tasks: contains_all_fields.yml
+ vars:
+ dict_to_check: "{{ item }}"
+ loop: "{{
+ only_check_first
+ | default(True)
+ | bool
+ | ternary([ module_info.modules[0] ], module_info.modules)
+ }}"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/tasks/contains_all_fields.yml b/ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/tasks/contains_all_fields.yml
new file mode 100644
index 000000000..20750e003
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/tasks/contains_all_fields.yml
@@ -0,0 +1,13 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2020, Brian Scholer <@briantist>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: Check for key ('{{ key }}') in result
+ assert:
+ that: key in dict_to_check
+ quiet: yes
+ fail_msg: "'{{ key }}' not found in dict."
+ loop_control:
+ loop_var: key
+ loop: "{{ expected_fields }}"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/tasks/main.yml
new file mode 100644
index 000000000..21ed04a21
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/tasks/main.yml
@@ -0,0 +1,49 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2020, Brian Scholer <@briantist>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: Reset repositories
+ ansible.windows.win_shell: |
+ Get-PSRepository | Unregister-PSRepository
+ Register-PSRepository -Default
+
+- name: Set up directory repository
+ ansible.windows.win_copy:
+ src: "{{ role_path }}/files/"
+ dest: "{{ repo_path }}"
+ force: no
+
+- name: Register repository
+ community.windows.win_psrepository:
+ name: "{{ repository_name }}"
+ source_location: "{{ repo_path }}"
+ installation_policy: trusted
+
+- block:
+ - name: Install Modules
+ community.windows.win_psmodule:
+ name: "{{ item }}"
+ state: latest
+ repository: "{{ repository_name }}"
+ loop: "{{ modules_to_install }}"
+
+ - name: Run Tests
+ import_tasks: tests.yml
+
+ - name: Run Tests (check mode)
+ import_tasks: tests.yml
+ vars:
+ run_check_mode: True
+
+ always:
+ - name: Remove Modules
+ community.windows.win_psmodule:
+ name: "{{ item }}"
+ state: absent
+ loop: "{{ modules_to_install }}"
+
+ - name: Reset repositories
+ ansible.windows.win_shell: |
+ Get-PSRepository | Unregister-PSRepository
+ Register-PSRepository -Default
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/tasks/tests.yml
new file mode 100644
index 000000000..688c994d2
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psmodule_info/tasks/tests.yml
@@ -0,0 +1,85 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2020, Brian Scholer <@briantist>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: Get info on a named module
+ vars:
+ expected_modules:
+ - "{{ builtin_modules[0] }}"
+ block:
+ - name: Get single module {{ suffix }}
+ community.windows.win_psmodule_info:
+ name: "{{ expected_modules[0] }}"
+ register: module_info
+
+ - include_tasks: common.yml
+
+ # block
+ check_mode: "{{ run_check_mode }}"
+
+- name: Get info on modules by wildcard match
+ vars:
+ wildcard: "Microsoft.PowerShell.*"
+ expected_modules: "{{ builtin_modules }}"
+ block:
+ - name: Get multiple modules by wildcard {{ suffix }}
+ community.windows.win_psmodule_info:
+ name: "{{ wildcard }}"
+ register: module_info
+
+ - include_tasks: common.yml
+
+ # block
+ check_mode: "{{ run_check_mode }}"
+
+- name: Get info on modules by repository
+ vars:
+ repository: "{{ repository_name }}"
+ expected_modules: "{{ modules_to_install }}"
+ block:
+ - name: Get multiple modules by repository {{ suffix }}
+ community.windows.win_psmodule_info:
+ repository: "{{ repository }}"
+ register: module_info
+
+ - include_tasks: common.yml
+
+ # block
+ check_mode: "{{ run_check_mode }}"
+
+- name: Get info on modules by repository and name pattern
+ vars:
+ wildcard: "*t"
+ repository: "{{ repository_name }}"
+ expected_modules:
+ - "AnsibleVault"
+ block:
+ - name: Get multiple modules by wildcard and repository {{ suffix }}
+ community.windows.win_psmodule_info:
+ name: "{{ wildcard }}"
+ repository: "{{ repository }}"
+ register: module_info
+
+ - include_tasks: common.yml
+
+ # block
+ check_mode: "{{ run_check_mode }}"
+
+- name: Get info on all modules
+ vars:
+ expected_modules: "{{ sample_modules }}"
+ block:
+ - name: Get all modules {{ suffix }}
+ community.windows.win_psmodule_info:
+ register: module_info
+
+ - include_tasks: common.yml
+
+ # one last time checking all the fields
+ - include_tasks: common.yml
+ vars:
+ only_check_first: False
+
+ # block
+ check_mode: "{{ run_check_mode }}"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psrepository/aliases b/ansible_collections/community/windows/tests/integration/targets/win_psrepository/aliases
new file mode 100644
index 000000000..0d6b4f220
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psrepository/aliases
@@ -0,0 +1,2 @@
+shippable/windows/group4
+needs/httptester
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psrepository/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_psrepository/defaults/main.yml
new file mode 100644
index 000000000..55e53a535
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psrepository/defaults/main.yml
@@ -0,0 +1,25 @@
+---
+repository_name: My Get
+repository_source_location: https://www.nuget.org/api/v2
+repository_publish_location: '{{ repository_source_location }}/fake/publish'
+repository_script_source_location: '{{ repository_source_location }}/fake/script'
+repository_script_publish_location: '{{ repository_source_location }}/fake/script/publish'
+
+repository_source_location2: '{{ remote_tmp_dir }}'
+
+redirect_url: http://{{ httpbin_host }}/redirect
+redirect_expected_target: http://{{ httpbin_host }}/get
+
+redirect_publish_url: http://{{ httpbin_host }}/redirect-to?url=http%3A%2F%2F{{ httpbin_host }}%2Fcache&status_code=307
+redirect_publish_expected_target: http://{{ httpbin_host }}/cache
+
+redirect_script_source_url: http://{{ httpbin_host }}/redirect-to?url=http%3A%2F%2F{{ httpbin_host }}%2Fxml&status_code=301
+redirect_script_source_expected_target: http://{{ httpbin_host }}/xml
+
+redirect_script_publish_url: http://{{ httpbin_host }}/redirect-to?url=http%3A%2F%2F{{ httpbin_host }}%2Fjson&status_code=302
+redirect_script_publish_expected_target: http://{{ httpbin_host }}/json
+
+repository_source_location_alt: http://{{ httpbin_host }}/response-headers
+repository_publish_location_alt: http://{{ httpbin_host }}/gzip
+repository_script_source_location_alt: http://{{ httpbin_host }}/html
+repository_script_publish_location_alt: http://{{ httpbin_host }}/deflate
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psrepository/meta/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_psrepository/meta/main.yml
new file mode 100644
index 000000000..9e7a71888
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psrepository/meta/main.yml
@@ -0,0 +1,4 @@
+dependencies:
+- setup_http_tests
+- setup_remote_tmp_dir
+- setup_win_psget
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psrepository/tasks/get_repo_info.yml b/ansible_collections/community/windows/tests/integration/targets/win_psrepository/tasks/get_repo_info.yml
new file mode 100644
index 000000000..999febcc6
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psrepository/tasks/get_repo_info.yml
@@ -0,0 +1,17 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2020, Brian Scholer <@briantist>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: Retrieve Repository Manually
+ ansible.windows.win_shell: |
+ $repo = Get-PSRepository -Name {{ repository_name | quote }} -ErrorAction SilentlyContinue
+ @{
+ repo = $repo
+ exists = $repo -as [bool]
+ } | ConvertTo-Json -Depth 5
+ register: _retrieve_repo_result
+
+- name: Set Repo Response Variable
+ set_fact:
+ "{{ repo_result_var | default('repo_result') }}": "{{ _retrieve_repo_result.stdout | from_json }}"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psrepository/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_psrepository/tasks/main.yml
new file mode 100644
index 000000000..0afdfbd2a
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psrepository/tasks/main.yml
@@ -0,0 +1,18 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2018, Wojciech Sciesinski <wojciech[at]sciesinski[dot]net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+---
+- name: unregister the repository
+ ansible.windows.win_shell: Unregister-PSRepository {{ repository_name | quote }} -ErrorAction SilentlyContinue
+
+- block:
+ - name: run all tests
+ include_tasks: tests.yml
+
+ - name: run update and force behavior tests
+ include_tasks: update_and_force.yml
+ always:
+ - name: ensure test repo is unregistered
+ ansible.windows.win_shell: Unregister-PSRepository {{ repository_name | quote }} -ErrorAction SilentlyContinue
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psrepository/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_psrepository/tasks/tests.yml
new file mode 100644
index 000000000..0fa63d9d0
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psrepository/tasks/tests.yml
@@ -0,0 +1,200 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2018, Wojciech Sciesinski <wojciech[at]sciesinski[dot]net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+---
+
+- name: check adding of repository defaults - check mode
+ win_psrepository:
+ name: "{{ repository_name }}"
+ source: "{{ repository_source_location }}"
+ state: present
+ check_mode: True
+ register: adding_repository_check
+
+- name: get result of adding repository defaults - check mode
+ ansible.windows.win_shell: (Get-PSRepository -Name {{ repository_name | quote }} -ErrorAction SilentlyContinue | Measure-Object).Count
+ changed_when: false
+ register: result_adding_repository_check
+
+- name: test adding repository defaults - check mode
+ assert:
+ that:
+ - adding_repository_check is changed
+ - result_adding_repository_check.stdout_lines[0] == '0'
+
+- name: check adding repository defaults
+ win_psrepository:
+ name: "{{ repository_name }}"
+ source: "{{ repository_source_location }}"
+ state: present
+ register: adding_repository
+
+- name: get result of adding repository defaults
+ ansible.windows.win_shell: |
+ $repo = Get-PSRepository -Name {{ repository_name | quote }}
+ ($repo | Measure-Object).Count
+ $repo.SourceLocation
+ $repo.InstallationPolicy
+ register: result_adding_repository
+
+- name: test adding repository defaults
+ assert:
+ that:
+ - adding_repository is changed
+ - result_adding_repository.stdout_lines[0] == '1'
+ - result_adding_repository.stdout_lines[1] == repository_source_location
+ - result_adding_repository.stdout_lines[2] == 'Trusted'
+
+- name: check adding repository defaults - idempotent
+ win_psrepository:
+ name: "{{ repository_name }}"
+ source: "{{ repository_source_location }}"
+ state: present
+ register: adding_repository_again
+
+- name: test check adding repository defaults - idempotent
+ assert:
+ that:
+ - adding_repository_again is not changed
+
+- name: change InstallationPolicy - check mode
+ win_psrepository:
+ name: "{{ repository_name }}"
+ source: "{{ repository_source_location }}"
+ installation_policy: untrusted
+ check_mode: True
+ register: change_installation_policy_check
+
+- name: get result of change InstallationPolicy - check mode
+ ansible.windows.win_shell: '(Get-PSRepository -Name {{ repository_name | quote }}).InstallationPolicy'
+ changed_when: false
+ register: result_change_installation_policy_check
+
+- name: test change InstallationPolicy - check mode
+ assert:
+ that:
+ - change_installation_policy_check is changed
+ - result_change_installation_policy_check.stdout | trim == 'Trusted'
+
+- name: change InstallationPolicy
+ win_psrepository:
+ name: "{{ repository_name }}"
+ source: "{{ repository_source_location }}"
+ installation_policy: untrusted
+ register: change_installation_policy
+
+- name: get result of change InstallationPolicy
+ ansible.windows.win_shell: '(Get-PSRepository -Name {{ repository_name | quote }}).InstallationPolicy'
+ changed_when: false
+ register: result_change_installation_policy
+
+- name: test change InstallationPolicy
+ assert:
+ that:
+ - change_installation_policy is changed
+ - result_change_installation_policy.stdout | trim == 'Untrusted'
+
+- name: change InstallationPolicy - idempotent
+ win_psrepository:
+ name: "{{ repository_name }}"
+ source: "{{ repository_source_location }}"
+ installation_policy: untrusted
+ register: change_installation_policy_again
+
+- name: test change InstallationPolicy - idempotent
+ assert:
+ that:
+ - change_installation_policy_again is not changed
+
+- name: change source - check mode
+ win_psrepository:
+ name: "{{ repository_name }}"
+ source: "{{ repository_source_location2 }}"
+ state: present
+ check_mode: True
+ register: change_source_check
+
+- name: get result of change source - check mode
+ ansible.windows.win_shell: |
+ $repo = Get-PSRepository -Name {{ repository_name | quote }}
+ $repo.SourceLocation
+ $repo.InstallationPolicy
+ changed_when: False
+ register: result_change_source_check
+
+- name: test change source - check mode
+ assert:
+ that:
+ - change_source_check is changed
+ - result_change_source_check.stdout_lines[0] == repository_source_location
+ - result_change_source_check.stdout_lines[1] == 'Untrusted'
+
+- name: change source
+ win_psrepository:
+ name: "{{ repository_name }}"
+ source: "{{ repository_source_location2 }}"
+ state: present
+ register: change_source
+
+- name: get result of change source
+ ansible.windows.win_shell: |
+ $repo = Get-PSRepository -Name {{ repository_name | quote }}
+ $repo.SourceLocation
+ $repo.InstallationPolicy
+ changed_when: False
+ register: result_change_source
+
+- name: test change source
+ assert:
+ that:
+ - change_source is changed
+ - result_change_source.stdout_lines[0] == repository_source_location2
+ - result_change_source.stdout_lines[1] == 'Untrusted'
+
+- name: remove repository - check mode
+ win_psrepository:
+ name: "{{ repository_name }}"
+ state: absent
+ check_mode: True
+ register: removing_repository_check
+
+- name: get result of remove repository - check mode
+ ansible.windows.win_shell: '(Get-PSRepository -Name {{ repository_name | quote }} -ErrorAction SilentlyContinue | Measure-Object).Count'
+ changed_when: false
+ register: result_removing_repository_check
+
+- name: test remove repository - check mode
+ assert:
+ that:
+ - removing_repository_check is changed
+ - result_removing_repository_check.stdout | trim == '1'
+
+- name: remove repository
+ win_psrepository:
+ name: "{{ repository_name }}"
+ state: absent
+ register: removing_repository
+
+- name: get result of remove repository
+ ansible.windows.win_shell: '(Get-PSRepository -Name {{ repository_name | quote }} -ErrorAction SilentlyContinue | Measure-Object).Count'
+ changed_when: false
+ register: result_removing_repository
+
+- name: test remove repository
+ assert:
+ that:
+ - removing_repository is changed
+ - result_removing_repository.stdout | trim == '0'
+
+- name: remove repository - idempotent
+ win_psrepository:
+ name: "{{ repository_name }}"
+ state: absent
+ register: remove_repository_again
+
+- name: test remove repository - idempotent
+ assert:
+ that:
+ - remove_repository_again is not changed
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psrepository/tasks/update_and_force.yml b/ansible_collections/community/windows/tests/integration/targets/win_psrepository/tasks/update_and_force.yml
new file mode 100644
index 000000000..ca78770c7
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psrepository/tasks/update_and_force.yml
@@ -0,0 +1,368 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2020, Brian Scholer <@briantist>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: Tests for creating a repository with all locations set
+ block:
+ - name: Add a repository with all locations set (check mode)
+ win_psrepository:
+ name: "{{ repository_name }}"
+ source_location: "{{ repository_source_location }}"
+ publish_location: "{{ repository_publish_location }}"
+ script_source_location: "{{ repository_script_source_location }}"
+ script_publish_location: "{{ repository_script_publish_location }}"
+ register: all_register_check
+ check_mode: True
+
+ - name: Assert that task is changed (check mode)
+ assert:
+ that:
+ - all_register_check is changed
+
+ - import_tasks: get_repo_info.yml
+
+ - name: Assert that the repository was not created (check mode)
+ assert:
+ that:
+ - not repo_result.exists
+
+ - name: Add a repository with all locations set
+ win_psrepository:
+ name: "{{ repository_name }}"
+ source_location: "{{ repository_source_location }}"
+ publish_location: "{{ repository_publish_location }}"
+ script_source_location: "{{ repository_script_source_location }}"
+ script_publish_location: "{{ repository_script_publish_location }}"
+ register: all_register_check
+
+ - name: Assert that task is changed
+ assert:
+ that:
+ - all_register_check is changed
+
+ - import_tasks: get_repo_info.yml
+
+ - name: Assert that the repository was created with expected locations
+ assert:
+ that:
+ - repo_result.exists
+ - repo_result.repo.SourceLocation == repository_source_location
+ - repo_result.repo.PublishLocation == repository_publish_location
+ - repo_result.repo.ScriptSourceLocation == repository_script_source_location
+ - repo_result.repo.ScriptPublishLocation == repository_script_publish_location
+
+ - name: Add a repository with all locations set again (check mode)
+ win_psrepository:
+ name: "{{ repository_name }}"
+ source_location: "{{ repository_source_location }}"
+ publish_location: "{{ repository_publish_location }}"
+ script_source_location: "{{ repository_script_source_location }}"
+ script_publish_location: "{{ repository_script_publish_location }}"
+ register: all_register_check
+ check_mode: True
+
+ - name: Assert that task is not changed
+ assert:
+ that:
+ - all_register_check is not changed
+
+- name: Tests for upating individual locations without changing existing ones
+ block:
+ - name: Update source location
+ block:
+ - name: Update source_location only (check mode)
+ win_psrepository:
+ name: "{{ repository_name }}"
+ source_location: "{{ repository_source_location_alt }}"
+ register: single_update_check
+ check_mode: True
+
+ - name: Assert that task is changed (check mode)
+ assert:
+ that:
+ - single_update_check is changed
+
+ - import_tasks: get_repo_info.yml
+
+ - name: Assert that source location was not updated (check mode)
+ assert:
+ that:
+ - repo_result.exists
+ - repo_result.repo.SourceLocation != repository_source_location_alt
+ - repo_result.repo.PublishLocation == repository_publish_location
+ - repo_result.repo.ScriptSourceLocation == repository_script_source_location
+ - repo_result.repo.ScriptPublishLocation == repository_script_publish_location
+
+ - name: Update source_location only
+ win_psrepository:
+ name: "{{ repository_name }}"
+ source_location: "{{ repository_source_location_alt }}"
+ register: single_update_check
+
+ - name: Assert that task is changed
+ assert:
+ that:
+ - single_update_check is changed
+
+ - import_tasks: get_repo_info.yml
+
+ - name: Assert that source location was updated
+ assert:
+ that:
+ - repo_result.exists
+ - repo_result.repo.SourceLocation == repository_source_location_alt
+ - repo_result.repo.PublishLocation == repository_publish_location
+ - repo_result.repo.ScriptSourceLocation == repository_script_source_location
+ - repo_result.repo.ScriptPublishLocation == repository_script_publish_location
+
+ - name: Update publish location
+ block:
+ - name: Update publish_location only (check mode)
+ win_psrepository:
+ name: "{{ repository_name }}"
+ publish_location: "{{ repository_publish_location_alt }}"
+ register: single_update_check
+ check_mode: True
+
+ - name: Assert that task is changed (check mode)
+ assert:
+ that:
+ - single_update_check is changed
+
+ - import_tasks: get_repo_info.yml
+
+ - name: Assert that publish location was not updated (check mode)
+ assert:
+ that:
+ - repo_result.exists
+ - repo_result.repo.SourceLocation == repository_source_location_alt
+ - repo_result.repo.PublishLocation != repository_publish_location_alt
+ - repo_result.repo.ScriptSourceLocation == repository_script_source_location
+ - repo_result.repo.ScriptPublishLocation == repository_script_publish_location
+
+ - name: Update publish_location only
+ win_psrepository:
+ name: "{{ repository_name }}"
+ publish_location: "{{ repository_publish_location_alt }}"
+ register: single_update_check
+
+ - name: Assert that task is changed
+ assert:
+ that:
+ - single_update_check is changed
+
+ - import_tasks: get_repo_info.yml
+
+ - name: Assert that publish location was updated
+ assert:
+ that:
+ - repo_result.exists
+ - repo_result.repo.SourceLocation == repository_source_location_alt
+ - repo_result.repo.PublishLocation == repository_publish_location_alt
+ - repo_result.repo.ScriptSourceLocation == repository_script_source_location
+ - repo_result.repo.ScriptPublishLocation == repository_script_publish_location
+
+ - name: Update script source location
+ block:
+ - name: Update script_source_location only (check mode)
+ win_psrepository:
+ name: "{{ repository_name }}"
+ script_source_location: "{{ repository_script_source_location_alt }}"
+ register: single_update_check
+ check_mode: True
+
+ - name: Assert that task is changed (check mode)
+ assert:
+ that:
+ - single_update_check is changed
+
+ - import_tasks: get_repo_info.yml
+
+ - name: Assert that script source location was not updated (check mode)
+ assert:
+ that:
+ - repo_result.exists
+ - repo_result.repo.SourceLocation == repository_source_location_alt
+ - repo_result.repo.PublishLocation == repository_publish_location_alt
+ - repo_result.repo.ScriptSourceLocation != repository_script_source_location_alt
+ - repo_result.repo.ScriptPublishLocation == repository_script_publish_location
+
+ - name: Update script_source_location only
+ win_psrepository:
+ name: "{{ repository_name }}"
+ script_source_location: "{{ repository_script_source_location_alt }}"
+ register: single_update_check
+
+ - name: Assert that task is changed
+ assert:
+ that:
+ - single_update_check is changed
+
+ - import_tasks: get_repo_info.yml
+
+ - name: Assert that script source location was updated
+ assert:
+ that:
+ - repo_result.exists
+ - repo_result.repo.SourceLocation == repository_source_location_alt
+ - repo_result.repo.PublishLocation == repository_publish_location_alt
+ - repo_result.repo.ScriptSourceLocation == repository_script_source_location_alt
+ - repo_result.repo.ScriptPublishLocation == repository_script_publish_location
+
+ - name: Update script publish location
+ block:
+ - name: Update script_publish_location only (check mode)
+ win_psrepository:
+ name: "{{ repository_name }}"
+ script_publish_location: "{{ repository_script_publish_location_alt }}"
+ register: single_update_check
+ check_mode: True
+
+ - name: Assert that task is changed (check mode)
+ assert:
+ that:
+ - single_update_check is changed
+
+ - import_tasks: get_repo_info.yml
+
+ - name: Assert that script publish location was not updated (check mode)
+ assert:
+ that:
+ - repo_result.exists
+ - repo_result.repo.SourceLocation == repository_source_location_alt
+ - repo_result.repo.PublishLocation == repository_publish_location_alt
+ - repo_result.repo.ScriptSourceLocation == repository_script_source_location_alt
+ - repo_result.repo.ScriptPublishLocation != repository_script_publish_location_alt
+
+ - name: Update script_publish_location only
+ win_psrepository:
+ name: "{{ repository_name }}"
+ script_publish_location: "{{ repository_script_publish_location_alt }}"
+ register: single_update_check
+
+ - name: Assert that task is changed
+ assert:
+ that:
+ - single_update_check is changed
+
+ - import_tasks: get_repo_info.yml
+
+ - name: Assert that script publish location was updated
+ assert:
+ that:
+ - repo_result.exists
+ - repo_result.repo.SourceLocation == repository_source_location_alt
+ - repo_result.repo.PublishLocation == repository_publish_location_alt
+ - repo_result.repo.ScriptSourceLocation == repository_script_source_location_alt
+ - repo_result.repo.ScriptPublishLocation == repository_script_publish_location_alt
+
+- name: Tests for using force
+ block:
+ - name: Ensure repository is not unnecessarily re-registered (check mode)
+ win_psrepository:
+ force: True
+ name: "{{ repository_name }}"
+ source_location: "{{ repository_source_location_alt }}"
+ publish_location: "{{ repository_publish_location_alt }}"
+ script_source_location: "{{ repository_script_source_location_alt }}"
+ script_publish_location: "{{ repository_script_publish_location_alt }}"
+ register: force_check
+ check_mode: True
+
+ - name: Assert that task is not changed (check mode)
+ assert:
+ that:
+ - force_check is not changed
+
+ - import_tasks: get_repo_info.yml
+
+ - name: Assert that repository settings remain identical (check mode)
+ assert:
+ that:
+ - repo_result.exists
+ - repo_result.repo.SourceLocation == repository_source_location_alt
+ - repo_result.repo.PublishLocation == repository_publish_location_alt
+ - repo_result.repo.ScriptSourceLocation == repository_script_source_location_alt
+ - repo_result.repo.ScriptPublishLocation == repository_script_publish_location_alt
+
+ - name: Ensure repository is not unnecessarily re-registered
+ win_psrepository:
+ force: True
+ name: "{{ repository_name }}"
+ source_location: "{{ repository_source_location_alt }}"
+ publish_location: "{{ repository_publish_location_alt }}"
+ script_source_location: "{{ repository_script_source_location_alt }}"
+ script_publish_location: "{{ repository_script_publish_location_alt }}"
+ register: force_check
+
+ - name: Assert that task is not changed
+ assert:
+ that:
+ - force_check is not changed
+
+ - import_tasks: get_repo_info.yml
+
+ - name: Assert that repository settings remain identical
+ assert:
+ that:
+ - repo_result.exists
+ - repo_result.repo.SourceLocation == repository_source_location_alt
+ - repo_result.repo.PublishLocation == repository_publish_location_alt
+ - repo_result.repo.ScriptSourceLocation == repository_script_source_location_alt
+ - repo_result.repo.ScriptPublishLocation == repository_script_publish_location_alt
+
+ - name: Set only two locations (check mode)
+ win_psrepository:
+ force: True
+ name: "{{ repository_name }}"
+ source_location: "{{ repository_source_location }}"
+ script_source_location: "{{ repository_script_source_location }}"
+ register: force_check
+ check_mode: True
+
+ - name: Assert that task is changed (check mode)
+ assert:
+ that:
+ - force_check is changed
+
+ - import_tasks: get_repo_info.yml
+
+ - name: Assert that repository settings remain identical (check mode)
+ assert:
+ that:
+ - repo_result.exists
+ - repo_result.repo.SourceLocation == repository_source_location_alt
+ - repo_result.repo.PublishLocation == repository_publish_location_alt
+ - repo_result.repo.ScriptSourceLocation == repository_script_source_location_alt
+ - repo_result.repo.ScriptPublishLocation == repository_script_publish_location_alt
+
+ - name: Set only two locations
+ win_psrepository:
+ force: True
+ name: "{{ repository_name }}"
+ source_location: "{{ repository_source_location }}"
+ script_source_location: "{{ repository_script_source_location }}"
+ register: force_check
+
+ - name: Assert that task is changed
+ assert:
+ that:
+ - force_check is changed
+
+ - import_tasks: get_repo_info.yml
+
+ - name: Assert that repository settings were updated
+ assert:
+ that:
+ - repo_result.exists
+ - repo_result.repo.SourceLocation == repository_source_location
+ - repo_result.repo.ScriptSourceLocation == repository_script_source_location
+ # these won't be blank because PowerShellGet tries to discover publish locations based on sources
+ - repo_result.repo.PublishLocation != repository_publish_location_alt
+ - repo_result.repo.ScriptPublishLocation != repository_script_publish_location_alt
+
+- name: remove repository (update and force tests)
+ win_psrepository:
+ name: "{{ repository_name }}"
+ state: absent
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/aliases b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/aliases
new file mode 100644
index 000000000..215e0b069
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/aliases
@@ -0,0 +1 @@
+shippable/windows/group4
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/defaults/main.yml
new file mode 100644
index 000000000..3cfe90d68
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/defaults/main.yml
@@ -0,0 +1,12 @@
+---
+user_password: 'gEYB#f74MslYcz&*1!*2WDM65!i&4*H'
+test_users:
+ - name: repo_copy1
+ - name: repo_copy2
+ profile: '{{ remote_tmp_dir }}\odd_dir'
+ - name: copy_repo3
+
+test_repos:
+ - PSGallery
+ - FakeGet
+ - FakeFileServer
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/files/SampleRepositories.xml b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/files/SampleRepositories.xml
new file mode 100644
index 000000000..162c3ea8f
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/files/SampleRepositories.xml
@@ -0,0 +1,94 @@
+<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04">
+ <Obj RefId="0">
+ <TN RefId="0">
+ <T>System.Collections.Hashtable</T>
+ <T>System.Object</T>
+ </TN>
+ <DCT>
+ <En>
+ <S N="Key">FakeFileServer</S>
+ <Obj N="Value" RefId="1">
+ <TN RefId="1">
+ <T>Microsoft.PowerShell.Commands.PSRepository</T>
+ <T>System.Management.Automation.PSCustomObject</T>
+ <T>System.Object</T>
+ </TN>
+ <MS>
+ <S N="Name">FakeFileServer</S>
+ <S N="SourceLocation">\\domain\share\repo\</S>
+ <S N="PublishLocation">\\domain\share\repo\</S>
+ <S N="ScriptSourceLocation">\\domain\share\repo\</S>
+ <S N="ScriptPublishLocation">\\domain\share\repo\</S>
+ <B N="Trusted">false</B>
+ <B N="Registered">true</B>
+ <S N="InstallationPolicy">Untrusted</S>
+ <S N="PackageManagementProvider">NuGet</S>
+ <Obj N="ProviderOptions" RefId="2">
+ <TNRef RefId="0" />
+ <DCT />
+ </Obj>
+ </MS>
+ </Obj>
+ </En>
+ <En>
+ <S N="Key">PSGallery</S>
+ <Obj N="Value" RefId="3">
+ <TN RefId="2">
+ <T>Deserialized.Microsoft.PowerShell.Commands.PSRepository</T>
+ <T>Deserialized.System.Management.Automation.PSCustomObject</T>
+ <T>Deserialized.System.Object</T>
+ </TN>
+ <MS>
+ <S N="Name">PSGallery</S>
+ <S N="SourceLocation">https://www.powershellgallery.com/api/v2</S>
+ <S N="PublishLocation">https://www.powershellgallery.com/api/v2/package/</S>
+ <S N="ScriptSourceLocation">https://www.powershellgallery.com/api/v2/items/psscript</S>
+ <S N="ScriptPublishLocation">https://www.powershellgallery.com/api/v2/package/</S>
+ <Obj N="Trusted" RefId="4">
+ <TN RefId="3">
+ <T>System.Management.Automation.SwitchParameter</T>
+ <T>System.ValueType</T>
+ <T>System.Object</T>
+ </TN>
+ <ToString>False</ToString>
+ <Props>
+ <B N="IsPresent">false</B>
+ </Props>
+ </Obj>
+ <B N="Registered">true</B>
+ <S N="InstallationPolicy">Untrusted</S>
+ <S N="PackageManagementProvider">NuGet</S>
+ <Obj N="ProviderOptions" RefId="5">
+ <TN RefId="4">
+ <T>Deserialized.System.Collections.Hashtable</T>
+ <T>Deserialized.System.Object</T>
+ </TN>
+ <DCT />
+ </Obj>
+ </MS>
+ </Obj>
+ </En>
+ <En>
+ <S N="Key">FakeGet</S>
+ <Obj N="Value" RefId="6">
+ <TNRef RefId="2" />
+ <MS>
+ <S N="Name">FakeGet</S>
+ <S N="SourceLocation">https://www.example.org/api/nuget/v2</S>
+ <S N="PublishLocation">https://www.example.org/api/nuget/v2/package/</S>
+ <S N="ScriptSourceLocation">https://www.exampe.org/api/nuget/v2/items/psscript</S>
+ <S N="ScriptPublishLocation">https://www.example.org/api/nuget/v2/package/</S>
+ <B N="Trusted">true</B>
+ <B N="Registered">true</B>
+ <S N="InstallationPolicy">Trusted</S>
+ <S N="PackageManagementProvider">NuGet</S>
+ <Obj N="ProviderOptions" RefId="7">
+ <TNRef RefId="4" />
+ <DCT />
+ </Obj>
+ </MS>
+ </Obj>
+ </En>
+ </DCT>
+ </Obj>
+</Objs>
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/meta/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/meta/main.yml
new file mode 100644
index 000000000..acc7fbcae
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/meta/main.yml
@@ -0,0 +1,3 @@
+dependencies:
+ - setup_remote_tmp_dir
+ - setup_win_psget
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/main.yml
new file mode 100644
index 000000000..80d6039ea
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/main.yml
@@ -0,0 +1,95 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2020, Brian Scholer <@briantist>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: Reset
+ import_tasks: reset.yml
+
+- name: Main block
+ module_defaults:
+ community.windows.win_psrepository_copy:
+ source: '{{ remote_tmp_dir }}\SampleRepositories.xml'
+ block:
+ # avoiding the use of win_psrepository / Register-PSRepository due to its strict target checking.
+ # in the end, this module always looks at the XML file, so we'll just put a pre-baked one in place.
+ - name: Put our source file in place
+ ansible.windows.win_copy:
+ src: SampleRepositories.xml
+ dest: "{{ remote_tmp_dir }}"
+ force: yes
+
+ - name: Copy repos with module defaults - check
+ community.windows.win_psrepository_copy:
+ register: status
+ check_mode: yes
+
+ - assert:
+ that: status is changed
+
+ - name: Copy repos with module defaults
+ community.windows.win_psrepository_copy:
+ register: status
+
+ - assert:
+ that: status is changed
+
+ - name: Copy repos with module defaults - again
+ community.windows.win_psrepository_copy:
+ register: status
+
+ - assert:
+ that: status is not changed
+
+ # these users should inherit the repositories via the Default profile
+ - name: Create test users
+ ansible.windows.win_user:
+ name: "{{ item.name }}"
+ profile: "{{ item.profile | default(omit) }}"
+ password: "{{ user_password }}"
+ groups:
+ - Administrators
+ loop: "{{ test_users }}"
+
+ #####################################
+ ## Begin inherited tests
+
+ - name: Test inherited repos via Default profile
+ include_tasks:
+ file: test_by_user.yml
+ apply:
+ vars:
+ user: "{{ item }}"
+ expected_repos: "{{ test_repos }}"
+ loop: "{{ test_users | map(attribute='name') | list }}"
+
+ ## End inherited tests
+ #####################################
+
+ - import_tasks: test_system_users.yml
+
+ - import_tasks: test_exclude_profile.yml
+
+ - import_tasks: test_include_profile.yml
+
+ - import_tasks: test_exclude_repo.yml
+
+ - import_tasks: test_include_repo.yml
+
+ always:
+ - name: Reset
+ import_tasks: reset.yml
+
+ - name: Remove test users
+ ansible.windows.win_user:
+ name: "{{ item.name }}"
+ state: absent
+ loop: "{{ test_users }}"
+
+ - name: Remove test profiles
+ import_tasks: remove_test_profiles.yml
+
+ - name: Remove sample file
+ ansible.windows.win_file:
+ path: '{{ remote_tmp_dir }}\SampleRepositories.xml'
+ state: absent
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/remove_test_profiles.yml b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/remove_test_profiles.yml
new file mode 100644
index 000000000..ab15d40fb
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/remove_test_profiles.yml
@@ -0,0 +1,42 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2020, Brian Scholer <@briantist>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+# removing a user doesn't remove their profile (which includes the filesystem directory and registry key).
+# without cleaning up, every CI run will create a new path and key and they will build up over time.
+# this finds all profiles on the system, via the registry, whose path basename starts with one of our test users
+# and then deletes the directory; if that was succesful, it deletes the registry key too.
+#
+# As a result this should also clean up after any old runs that left behind profiles, so an interrupted run
+# that didn't run the rescue block will still get cleaned up by the next when this runs again.
+
+- name: Remove all the test user profiles from the system
+ become: yes
+ become_user: SYSTEM
+ become_method: runas
+ ansible.windows.win_shell: |
+ $names = @'
+ {{ test_users | map(attribute='name') | list | to_json }}
+ '@ | ConvertFrom-Json
+ $regPL = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList'
+ $profiles = Get-ChildItem -LiteralPath $regPL
+
+ $profiles | ForEach-Object -Process {
+ $path = ($_ | Get-ItemProperty | Select-Object -ExpandProperty ProfileImagePath) -as [System.IO.DirectoryInfo]
+ :search foreach ($target in $names) {
+ if ($path.Name -match "^$target") {
+ $delReg=$true
+ if ($path.Exists) {
+ & cmd.exe /c rd /s /q $path.FullName
+ if (-not ($delReg=$?)) {
+ Write-Warning -Message "Couldn't remove '$path'"
+ }
+ }
+ if ($delReg) {
+ $_ | Remove-Item -Force -ErrorAction SilentlyContinue
+ }
+ break search
+ }
+ }
+ }
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/reset.yml b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/reset.yml
new file mode 100644
index 000000000..d985c2950
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/reset.yml
@@ -0,0 +1,22 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2020, Brian Scholer <@briantist>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: Remove the psrepositories for all profiles on the system
+ become: yes
+ become_user: SYSTEM
+ become_method: runas
+ ansible.windows.win_shell: |
+ $regPL = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList'
+ $default = Get-ItemProperty -LiteralPath $regPL | Select-Object -ExpandProperty Default
+ $profiles = (
+ @($default) +
+ (Get-ChildItem -LiteralPath $regPL | Get-ItemProperty | Select-Object -ExpandProperty ProfileImagePath)
+ ) -as [System.IO.DirectoryInfo[]]
+ $profiles |
+ Where-Object -Property Exists -EQ $true |
+ ForEach-Object -Process {
+ $p = [System.IO.Path]::Combine($_.FullName, 'AppData\Local\Microsoft\Windows\PowerShell\PowerShellGet\PSRepositories.xml')
+ Remove-Item -LiteralPath $p -Force -ErrorAction SilentlyContinue
+ }
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/test_by_user.yml b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/test_by_user.yml
new file mode 100644
index 000000000..f5f76d20b
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/test_by_user.yml
@@ -0,0 +1,32 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2020, Brian Scholer <@briantist>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: Get repository info
+ become: yes
+ become_user: "{{ user }}"
+ become_method: runas
+ community.windows.win_psrepository_info:
+ register: repos
+
+- name: Ensure expected repositories are present
+ assert:
+ that: repo in (repos.repositories | map(attribute='name') | list)
+ success_msg: "expected repository '{{ repo }}' was found for user '{{ user }}'"
+ fail_msg: "expected repository '{{ repo }}' was not found for user '{{ user }}'"
+ loop: "{{ expected_repos }}"
+ loop_control:
+ loop_var: repo
+
+- name: Ensure present repositories are expected
+ assert:
+ that: repo in expected_repos or repo == 'PSGallery'
+ # although not completely consistent depending on OS and/or PowerShellGet versions
+ # often calling Get-PSRepository will register PSGallery if it's missing, so we
+ # must be prepared for it to show up here "unexpectedly" by way of us querying :(
+ success_msg: "found expected repository '{{ repo }}' for user '{{ user }}'"
+ fail_msg: "found unexpected repository '{{ repo }}' for user '{{ user }}'"
+ loop: "{{ repos.repositories | map(attribute='name') | list }}"
+ loop_control:
+ loop_var: repo
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/test_exclude_profile.yml b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/test_exclude_profile.yml
new file mode 100644
index 000000000..19da14e1d
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/test_exclude_profile.yml
@@ -0,0 +1,58 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2020, Brian Scholer <@briantist>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+#####################################
+## Begin filter profile (exclusive) tests
+- name: Reset
+ import_tasks: reset.yml
+
+- name: Copy repos with excluded profiles - check
+ community.windows.win_psrepository_copy:
+ exclude_profiles: 'repo*'
+ register: status
+ check_mode: yes
+
+- assert:
+ that: status is changed
+
+- name: Copy repos with excluded profiles
+ community.windows.win_psrepository_copy:
+ exclude_profiles: 'repo*'
+ register: status
+
+- assert:
+ that: status is changed
+
+- name: Copy repos with excluded profiles - again
+ community.windows.win_psrepository_copy:
+ exclude_profiles: 'repo*'
+ register: status
+
+- assert:
+ that: status is not changed
+
+- name: Test filtered profiles (excluded)
+ include_tasks:
+ file: test_by_user.yml
+ apply:
+ vars:
+ user: "{{ item }}"
+ expected_repos: []
+ loop:
+ - repo_copy1
+ - repo_copy2
+
+- name: Test filtered profiles (not excluded)
+ include_tasks:
+ file: test_by_user.yml
+ apply:
+ vars:
+ user: "{{ item }}"
+ expected_repos: "{{ test_repos }}"
+ loop:
+ - copy_repo3
+
+## End filter profile (exclusive) tests
+#####################################
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/test_exclude_repo.yml b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/test_exclude_repo.yml
new file mode 100644
index 000000000..c85190243
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/test_exclude_repo.yml
@@ -0,0 +1,49 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2020, Brian Scholer <@briantist>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+#####################################
+## Begin filter repo (exclusive) tests
+
+- name: Reset
+ import_tasks: reset.yml
+
+- name: Copy filtered repos by exclusion - check
+ community.windows.win_psrepository_copy:
+ exclude: '*Server'
+ register: status
+ check_mode: yes
+
+- assert:
+ that: status is changed
+
+- name: Copy filtered repos by exclusion
+ community.windows.win_psrepository_copy:
+ exclude: '*Server'
+ register: status
+
+- assert:
+ that: status is changed
+
+- name: Copy filtered repos by exclusion - again
+ community.windows.win_psrepository_copy:
+ exclude: '*Server'
+ register: status
+
+- assert:
+ that: status is not changed
+
+- name: Test filtered repos (included)
+ include_tasks:
+ file: test_by_user.yml
+ apply:
+ vars:
+ user: "{{ item }}"
+ expected_repos:
+ - PSGallery
+ - FakeGet
+ loop: "{{ test_users | map(attribute='name') | list }}"
+
+## End filter repo (exclusive) tests
+#####################################
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/test_include_profile.yml b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/test_include_profile.yml
new file mode 100644
index 000000000..6e3d47b97
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/test_include_profile.yml
@@ -0,0 +1,59 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2020, Brian Scholer <@briantist>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+#####################################
+## Begin filter profile (inclusive) tests
+
+- name: Reset
+ import_tasks: reset.yml
+
+- name: Copy repos with filtered profiles - check
+ community.windows.win_psrepository_copy:
+ profiles: 'repo*'
+ register: status
+ check_mode: yes
+
+- assert:
+ that: status is changed
+
+- name: Copy repos with filtered profiles
+ community.windows.win_psrepository_copy:
+ profiles: 'repo*'
+ register: status
+
+- assert:
+ that: status is changed
+
+- name: Copy repos with filtered profiles - again
+ community.windows.win_psrepository_copy:
+ profiles: 'repo*'
+ register: status
+
+- assert:
+ that: status is not changed
+
+- name: Test filtered profiles (included)
+ include_tasks:
+ file: test_by_user.yml
+ apply:
+ vars:
+ user: "{{ item }}"
+ expected_repos: "{{ test_repos }}"
+ loop:
+ - repo_copy1
+ - repo_copy2
+
+- name: Test filtered profiles (not included)
+ include_tasks:
+ file: test_by_user.yml
+ apply:
+ vars:
+ user: "{{ item }}"
+ expected_repos: []
+ loop:
+ - copy_repo3
+
+## End filter profile (inclusive) tests
+#####################################
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/test_include_repo.yml b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/test_include_repo.yml
new file mode 100644
index 000000000..3bc392931
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/test_include_repo.yml
@@ -0,0 +1,49 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2020, Brian Scholer <@briantist>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+#####################################
+## Begin filter repo (inclusive) tests
+
+- name: Reset
+ import_tasks: reset.yml
+
+- name: Copy filtered repos - check
+ community.windows.win_psrepository_copy:
+ name: '*G*'
+ register: status
+ check_mode: yes
+
+- assert:
+ that: status is changed
+
+- name: Copy filtered repos
+ community.windows.win_psrepository_copy:
+ name: '*G*'
+ register: status
+
+- assert:
+ that: status is changed
+
+- name: Copy filtered repos - again
+ community.windows.win_psrepository_copy:
+ name: '*G*'
+ register: status
+
+- assert:
+ that: status is not changed
+
+- name: Test filtered repos (included)
+ include_tasks:
+ file: test_by_user.yml
+ apply:
+ vars:
+ user: "{{ item }}"
+ expected_repos:
+ - PSGallery
+ - FakeGet
+ loop: "{{ test_users | map(attribute='name') | list }}"
+
+## End filter repo (inclusive) tests
+#####################################
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/test_system_users.yml b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/test_system_users.yml
new file mode 100644
index 000000000..446ad4d1c
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_copy/tasks/test_system_users.yml
@@ -0,0 +1,68 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2020, Brian Scholer <@briantist>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+#####################################
+## Begin system user tests
+
+- name: Reset
+ import_tasks: reset.yml
+
+- name: Copy repos only to special system users - check
+ community.windows.win_psrepository_copy:
+ profiles:
+ - '*Service'
+ - 'systemprofile'
+ exclude_profiles: []
+ register: status
+ check_mode: yes
+
+- assert:
+ that: status is changed
+
+- name: Copy repos only to special system users
+ community.windows.win_psrepository_copy:
+ profiles:
+ - '*Service'
+ - 'systemprofile'
+ exclude_profiles: []
+ register: status
+
+- assert:
+ that: status is changed
+
+- name: Copy repos only to special system users - again
+ community.windows.win_psrepository_copy:
+ profiles:
+ - '*Service'
+ - 'systemprofile'
+ exclude_profiles: []
+ register: status
+
+- assert:
+ that: status is not changed
+
+- name: Test system users
+ include_tasks:
+ file: test_by_user.yml
+ apply:
+ vars:
+ user: "{{ 'SYSTEM' if item == 'systemprofile' else item }}"
+ expected_repos: "{{ test_repos }}"
+ loop:
+ - systemprofile
+ - LocalService
+ - NetworkService
+
+- name: Test other users
+ include_tasks:
+ file: test_by_user.yml
+ apply:
+ vars:
+ user: "{{ item }}"
+ expected_repos: []
+ loop: "{{ test_users | map(attribute='name') | list }}"
+
+## End system user tests
+#####################################
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psrepository_info/aliases b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_info/aliases
new file mode 100644
index 000000000..748bc3ed5
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_info/aliases
@@ -0,0 +1,3 @@
+shippable/windows/group3
+needs/httptester
+unstable
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psrepository_info/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_info/defaults/main.yml
new file mode 100644
index 000000000..13dac5dee
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_info/defaults/main.yml
@@ -0,0 +1,10 @@
+---
+run_check_mode: False
+suffix: "{{ '(check mode)' if run_check_mode else '' }}"
+default_repository_name: PSGallery
+
+second_repository_name: PowerShellGetDemo
+second_repository_source_location: https://www.nuget.org/api/v2
+
+third_repository_name: OtherRepo
+third_repository_source_location: http://{{ httpbin_host }}/get
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psrepository_info/meta/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_info/meta/main.yml
new file mode 100644
index 000000000..f050654c7
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_info/meta/main.yml
@@ -0,0 +1,3 @@
+dependencies:
+ - setup_http_tests
+ - setup_win_psget
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psrepository_info/tasks/contains_all_fields.yml b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_info/tasks/contains_all_fields.yml
new file mode 100644
index 000000000..6f3e6f500
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_info/tasks/contains_all_fields.yml
@@ -0,0 +1,21 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2020, Brian Scholer <@briantist>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: Check for key ('{{ key }}') in result
+ assert:
+ that: key in dict_to_check
+ loop_control:
+ loop_var: key
+ loop:
+ - name
+ - installation_policy
+ - package_management_provider
+ - provider_options
+ - publish_location
+ - source_location
+ - script_source_location
+ - script_publish_location
+ - registered
+ - trusted
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psrepository_info/tasks/empty.yml b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_info/tasks/empty.yml
new file mode 100644
index 000000000..9bc6d4c64
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_info/tasks/empty.yml
@@ -0,0 +1,19 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2020, Brian Scholer <@briantist>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: Tests against the empty set of repositories
+ block:
+ - name: Get repository info {{ suffix }}
+ win_psrepository_info:
+ register: repo_info
+
+ - name: Assert that the correct structure is returned {{ suffix }}
+ assert:
+ that:
+ - repo_info.repositories is defined
+ - repo_info.repositories is sequence()
+ - repo_info.repositories | length == 0
+ # block
+ check_mode: "{{ run_check_mode }}"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psrepository_info/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_info/tasks/main.yml
new file mode 100644
index 000000000..72427e211
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_info/tasks/main.yml
@@ -0,0 +1,51 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2020, Brian Scholer <@briantist>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: Unregister all repositories
+ ansible.windows.win_shell: |
+ Get-PSRepository | Unregister-PSRepository
+
+- block:
+ - name: Run Empty Tests
+ import_tasks: empty.yml
+
+ - name: Run Empty Tests (check mode)
+ import_tasks: empty.yml
+ vars:
+ run_check_mode: True
+
+ - name: Add the default repository
+ ansible.windows.win_shell: |
+ Register-PSRepository -Default
+
+ - name: Single Repository Tests
+ import_tasks: single.yml
+
+ - name: Single Repository Tests (check mode)
+ import_tasks: single.yml
+ vars:
+ run_check_mode: True
+
+ - name: Add two more repositories
+ ansible.windows.win_shell: |
+ Register-PSRepository -Name '{{ second_repository_name }}' -SourceLocation '{{ second_repository_source_location }}'
+ Register-PSRepository -Name '{{ third_repository_name }}' -SourceLocation '{{ third_repository_source_location }}'
+
+ - name: Multi Repository Tests
+ import_tasks: multiple.yml
+
+ - name: Multi Repository Tests (check mode)
+ import_tasks: multiple.yml
+ vars:
+ run_check_mode: True
+
+ always:
+ - name: Unregister all repositories
+ ansible.windows.win_shell: |
+ Get-PSRepository | Unregister-PSRepository
+
+ - name: Ensure only the default repository remains
+ ansible.windows.win_shell: |
+ Register-PSRepository -Default
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psrepository_info/tasks/multiple.yml b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_info/tasks/multiple.yml
new file mode 100644
index 000000000..8c5b986e7
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_info/tasks/multiple.yml
@@ -0,0 +1,37 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2020, Brian Scholer <@briantist>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: Tests against mutiple repositories
+ block:
+ - name: Get all repository info {{ suffix }}
+ win_psrepository_info:
+ register: repo_info
+
+ - name: Assert that the correct structure is returned {{ suffix }}
+ assert:
+ that:
+ - repo_info.repositories is defined
+ - repo_info.repositories is sequence()
+ - repo_info.repositories | length == 3
+
+ - include_tasks: contains_all_fields.yml
+ vars:
+ dict_to_check: "{{ item }}"
+ loop: "{{ repo_info.repositories }}"
+
+ - name: Get two repositories with a filter {{ suffix }}
+ win_psrepository_info:
+ name: P*
+ register: repo_info
+
+ - name: Assert that the correct two repositories were returned {{ suffix }}
+ assert:
+ that:
+ - repo_info.repositories | length == 2
+ - default_repository_name in (repo_info.repositories | map(attribute='name') | list)
+ - second_repository_name in (repo_info.repositories | map(attribute='name') | list)
+
+ # block
+ check_mode: "{{ run_check_mode }}"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psrepository_info/tasks/single.yml b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_info/tasks/single.yml
new file mode 100644
index 000000000..00071ec55
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psrepository_info/tasks/single.yml
@@ -0,0 +1,26 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2020, Brian Scholer <@briantist>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: Tests against a single repository ({{ default_repository_name }})
+ block:
+ - name: Get repository info {{ suffix }}
+ win_psrepository_info:
+ name: "{{ default_repository_name }}"
+ register: repo_info
+
+ - name: Assert that the correct structure is returned {{ suffix }}
+ assert:
+ that:
+ - repo_info.repositories is defined
+ - repo_info.repositories is sequence()
+ - repo_info.repositories | length == 1
+ - repo_info.repositories[0].name == default_repository_name
+
+ - include_tasks: contains_all_fields.yml
+ vars:
+ dict_to_check: "{{ repo_info.repositories[0] }}"
+
+ # block
+ check_mode: "{{ run_check_mode }}"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psscript/aliases b/ansible_collections/community/windows/tests/integration/targets/win_psscript/aliases
new file mode 100644
index 000000000..4f4664b68
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psscript/aliases
@@ -0,0 +1 @@
+shippable/windows/group5
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psscript/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_psscript/defaults/main.yml
new file mode 100644
index 000000000..010348236
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psscript/defaults/main.yml
@@ -0,0 +1,26 @@
+---
+repos:
+ - name: Repo1
+ path: '{{ remote_tmp_dir }}\Repo1'
+ policy: trusted
+ scripts:
+ - Test-One
+ - Test-Multi
+
+ - name: Repo2
+ path: '{{ remote_tmp_dir }}\Repo2'
+ policy: untrusted
+ scripts:
+ - Test-Two
+ - Test-Multi
+
+versions:
+ - 1.0.0
+ - 1.0.9
+ - 1.0.10
+ - 10.0.0
+ - 10.0.9
+ - 10.0.10
+
+earliest_version: 1.0.0
+latest_version: 10.0.10
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psscript/handlers/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_psscript/handlers/main.yml
new file mode 100644
index 000000000..83c4a490c
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psscript/handlers/main.yml
@@ -0,0 +1,22 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2020, Brian Scholer <@briantist>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: Clear Repositories
+ ansible.windows.win_shell: |
+ Get-PSRepository | Unregister-PSRepository
+
+- name: Add PSGallery
+ ansible.windows.win_shell: |
+ Register-PSRepository -Default
+
+- name: Clear Installed Scripts
+ ansible.windows.win_shell: |
+ Get-InstalledScript | Uninstall-Script -Force
+
+- name: Remove Directories
+ ansible.windows.win_file:
+ path: '{{ item.path }}'
+ state: absent
+ loop: "{{ repos }}"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psscript/meta/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_psscript/meta/main.yml
new file mode 100644
index 000000000..acc7fbcae
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psscript/meta/main.yml
@@ -0,0 +1,3 @@
+dependencies:
+ - setup_remote_tmp_dir
+ - setup_win_psget
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psscript/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_psscript/tasks/main.yml
new file mode 100644
index 000000000..97779ae0f
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psscript/tasks/main.yml
@@ -0,0 +1,13 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2020, Brian Scholer <@briantist>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: Setup local repositories
+ import_tasks: setup_repos.yml
+ tags:
+ - always
+ - setup
+
+- name: Run Tests
+ import_tasks: tests.yml \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psscript/tasks/script_info.yml b/ansible_collections/community/windows/tests/integration/targets/win_psscript/tasks/script_info.yml
new file mode 100644
index 000000000..d16993460
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psscript/tasks/script_info.yml
@@ -0,0 +1,81 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2020, Brian Scholer <@briantist>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: Get installed scripts
+ ansible.windows.win_shell: |
+ $pMachine = "$env:ProgramFiles\WindowsPowerShell\Scripts"
+ # 2012/2012R2 test environments seem to have blank values for some environment vars
+ $userStub = 'Documents\WindowsPowerShell\Scripts'
+ $userBase = if ($Home) {
+ $Home
+ }
+ elseif ($env:UserProfile) {
+ $env:UserProfile
+ }
+ elseif ($env:HomeDrive -and $env:HomePath) {
+ "${env:HomeDrive}${env:HomePath}\$userStub"
+ }
+ elseif ($env:UserName) {
+ $root = if ($env:SystemDrive) {
+ $env:SystemDrive
+ }
+ elseif ($emv:HomeDrive) {
+ $env:HomeDrive
+ }
+ else {
+ 'C:'
+ }
+ "${root}\Users\${env:UserName}"
+ }
+ $pUser = "${userBase}\${userStub}"
+
+ $scripts = Get-InstalledScript |
+ Select-Object Name,Version,InstalledLocation,Repository,@{
+ Name = 'current_user'
+ Expression = { $_.InstalledLocation -eq $pUser }
+ },
+ @{
+ Name = 'all_users'
+ Expression = { $_.InstalledLocation -eq $pMachine }
+ },
+ @{
+ # this is for troubleshooting tests
+ # 2012/2012R2 test environments seem to have blank values for some environment vars
+ Name = 'paths_to_compare'
+ Expression = {
+ @{
+ pUser = $pUser
+ pMachine = $pMachine
+ home = $Home
+ homedrive = $env:HOMEDRIVE
+ homepath = $env:HOMEPATH
+ providerhome = (Get-PSProvider -PSProvider FileSystem).Home
+ userprofile = $env:UserProfile
+ username = $env:UserName
+ }
+ }
+ }
+
+ if (-not $scripts) {
+ $scripts = @()
+ }
+
+ ConvertTo-Json -Depth 5 -InputObject ([object[]]$scripts)
+ register: _raw_info
+
+- name: Set script info var
+ set_fact:
+ "{{ script_info_var | default('scripts') }}": "{{
+ dict(
+ _raw_info.stdout
+ | from_json
+ | map(attribute='Name')
+ | list
+ | zip(
+ _raw_info.stdout
+ | from_json
+ )
+ )
+ }}"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psscript/tasks/setup_repos.yml b/ansible_collections/community/windows/tests/integration/targets/win_psscript/tasks/setup_repos.yml
new file mode 100644
index 000000000..94dea1871
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psscript/tasks/setup_repos.yml
@@ -0,0 +1,58 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2020, Brian Scholer <@briantist>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: Unregister all repositories
+ ansible.windows.win_shell: |
+ Get-PSRepository | Unregister-PSRepository
+ notify: Add PSGallery
+
+- name: Create repo folders
+ ansible.windows.win_file:
+ path: '{{ item.path }}'
+ state: directory
+ loop: "{{ repos }}"
+ notify: Remove Directories
+
+- name: Register repos
+ win_psrepository:
+ name: '{{ item.name }}'
+ source: '{{ item.path }}'
+ installation_policy: '{{ item.policy }}'
+ notify: Clear Repositories
+ loop: "{{ repos }}"
+
+- name: Create and Publish Scripts
+ ansible.windows.win_shell: |
+ $tmp = '{{ remote_tmp_dir }}'
+
+ # it looks like Tls12 is not added during the nuget bootstrapping process
+ # hitting connection closed errors during some tests. May be related to this:
+ # https://devblogs.microsoft.com/nuget/deprecating-tls-1-0-and-1-1-on-nuget-org/
+ [System.Net.ServicePointManager]::SecurityProtocol = `
+ [System.Net.ServicePointManager]::SecurityProtocol -bor
+ [System.Net.SecurityProtocolType]::SystemDefault -bor
+ [System.Net.SecurityProtocolType]::Tls11 -bor
+ [System.Net.SecurityProtocolType]::Tls12
+
+ {% for version in versions %}
+ {% for repo in repos %}
+ {% for script in repo.scripts %}
+
+ $script = '{{ script }}'
+ $repo = '{{ repo.name }}'
+ $ver = '{{ version }}'
+ $file = "${script}.ps1"
+ $out = $tmp | Join-Path -ChildPath $file
+
+ try {
+ New-ScriptFileInfo -Description $script -Version $ver -Path $out -Force
+ Publish-Script -Path $out -Repository $repo -Force
+ } finally {
+ Remove-Item -LiteralPath $out -Force -ErrorAction SilentlyContinue
+ }
+
+ {% endfor %}
+ {% endfor %}
+ {% endfor %}
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psscript/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_psscript/tasks/tests.yml
new file mode 100644
index 000000000..7376b3fa5
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psscript/tasks/tests.yml
@@ -0,0 +1,555 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2020, Brian Scholer <@briantist>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: Basic Tests Script 1
+ tags:
+ - basic1
+ vars:
+ script: Test-One
+ scope: all_users
+ expected:
+ repo: Repo1
+ version: "{{ latest_version }}"
+ block:
+ - name: Install a script (check mode)
+ win_psscript:
+ name: "{{ script }}"
+ scope: "{{ scope }}"
+ register: result
+ check_mode: True
+
+ - name: Assert task is changed (check mode)
+ assert:
+ that: result is changed
+
+ - import_tasks: script_info.yml
+
+ - name: Ensure nothing was installed (check mode)
+ assert:
+ that:
+ - scripts | length == 0
+ - script not in scripts
+
+ - name: Install a script
+ win_psscript:
+ name: "{{ script }}"
+ scope: "{{ scope }}"
+ register: result
+ notify: Clear Installed Scripts
+
+ - name: Assert task is changed
+ assert:
+ that: result is changed
+
+ - import_tasks: script_info.yml
+
+ - name: Ensure script was installed
+ assert:
+ that:
+ - scripts | length == 1
+ - script in scripts
+ - scripts[script].Version is version(expected.version, '==')
+ - scripts[script].Repository == expected.repo
+ - scripts[script][scope]
+
+ - name: Install script again (check mode)
+ win_psscript:
+ name: "{{ script }}"
+ scope: "{{ scope }}"
+ register: result
+ check_mode: True
+
+ - name: Assert task is not changed (check mode)
+ assert:
+ that: result is not changed
+
+- name: Basic Tests Script 2
+ tags:
+ - basic2
+ vars:
+ script: Test-Two
+ scope: current_user
+ expected:
+ repo: Repo2
+ version: "{{ latest_version }}"
+ block:
+ - name: Install a script (check mode)
+ win_psscript:
+ name: "{{ script }}"
+ scope: "{{ scope }}"
+ register: result
+ check_mode: True
+
+ - name: Assert task is changed (check mode)
+ assert:
+ that: result is changed
+
+ - import_tasks: script_info.yml
+
+ - name: Ensure nothing was installed (check mode)
+ assert:
+ that:
+ - scripts | length == 1
+ - script not in scripts
+
+ - name: Install a script
+ win_psscript:
+ name: "{{ script }}"
+ scope: "{{ scope }}"
+ register: result
+ notify: Clear Installed Scripts
+
+ - name: Assert task is changed
+ assert:
+ that: result is changed
+
+ - import_tasks: script_info.yml
+
+ - name: Ensure script was installed
+ assert:
+ that:
+ - scripts | length == 2
+ - script in scripts
+ - scripts[script].Version is version(expected.version, '==')
+ - scripts[script].Repository == expected.repo
+ - scripts[script][scope]
+
+ - name: Install script again (check mode)
+ win_psscript:
+ name: "{{ script }}"
+ scope: "{{ scope }}"
+ register: result
+ check_mode: True
+
+ - name: Assert task is not changed (check mode)
+ assert:
+ that: result is not changed
+
+- name: Removal Tests Script 1
+ tags:
+ - remove1
+ vars:
+ script: Test-One
+ state: absent
+ block:
+ - name: Remove Script (check mode)
+ win_psscript:
+ name: "{{ script }}"
+ state: "{{ state }}"
+ register: result
+ check_mode: True
+
+ - name: Assert task is changed (check mode)
+ assert:
+ that: result is changed
+
+ - import_tasks: script_info.yml
+
+ - name: Ensure script was not removed (check mode)
+ assert:
+ that:
+ - scripts | length == 2
+ - script in scripts
+
+ - name: Remove Script
+ win_psscript:
+ name: "{{ script }}"
+ state: "{{ state }}"
+ register: result
+
+ - name: Assert task is changed
+ assert:
+ that: result is changed
+
+ - import_tasks: script_info.yml
+
+ - name: Ensure script was removed
+ assert:
+ that:
+ - scripts | length == 1
+ - script not in scripts
+
+ - name: Remove Script Again (check mode)
+ win_psscript:
+ name: "{{ script }}"
+ state: "{{ state }}"
+ register: result
+ check_mode: True
+
+ - name: Assert task is not changed (check mode)
+ assert:
+ that: result is not changed
+
+- name: Removal Tests Script 2
+ tags:
+ - remove2
+ vars:
+ script: Test-Two
+ state: absent
+ block:
+ - name: Remove Script (check mode)
+ win_psscript:
+ name: "{{ script }}"
+ state: "{{ state }}"
+ register: result
+ check_mode: True
+
+ - name: Assert task is changed (check mode)
+ assert:
+ that: result is changed
+
+ - import_tasks: script_info.yml
+
+ - name: Ensure script was not removed (check mode)
+ assert:
+ that:
+ - scripts | length == 1
+ - script in scripts
+
+ - name: Remove Script
+ win_psscript:
+ name: "{{ script }}"
+ state: "{{ state }}"
+ register: result
+
+ - name: Assert task is changed
+ assert:
+ that: result is changed
+
+ - import_tasks: script_info.yml
+
+ - name: Ensure script was removed
+ assert:
+ that:
+ - scripts | length == 0
+ - script not in scripts
+
+ - name: Remove Script Again (check mode)
+ win_psscript:
+ name: "{{ script }}"
+ state: "{{ state }}"
+ register: result
+ check_mode: True
+
+ - name: Assert task is not changed (check mode)
+ assert:
+ that: result is not changed
+
+- name: Tests for Script in Multiple Repos
+ tags:
+ - multi
+ vars:
+ script: Test-Multi
+ scope: all_users
+ expected:
+ repo: Repo2
+ version: "{{ latest_version }}"
+ block:
+ - name: Install a script from multiple repos
+ win_psscript:
+ name: "{{ script }}"
+ scope: "{{ scope }}"
+ register: result
+ failed_when: result.msg is not search('Multiple scripts found')
+
+ - name: Install a script from multiple repos by chosing one (check mode)
+ win_psscript:
+ name: "{{ script }}"
+ scope: "{{ scope }}"
+ repository: "{{ expected.repo }}"
+ register: result
+ check_mode: True
+
+ - name: Assert task is changed (check mode)
+ assert:
+ that: result is changed
+
+ - import_tasks: script_info.yml
+
+ - name: Ensure nothing was installed (check mode)
+ assert:
+ that:
+ - scripts | length == 0
+ - script not in scripts
+
+ - name: Install a script from multiple repos by chosing one
+ win_psscript:
+ name: "{{ script }}"
+ scope: "{{ scope }}"
+ repository: "{{ expected.repo }}"
+ register: result
+ notify: Clear Installed Scripts
+
+ - name: Assert task is changed
+ assert:
+ that: result is changed
+
+ - import_tasks: script_info.yml
+
+ - name: Ensure script was installed
+ assert:
+ that:
+ - scripts | length == 1
+ - script in scripts
+ - scripts[script].Version is version(expected.version, '==')
+ - scripts[script].Repository == expected.repo
+ - scripts[script][scope]
+
+ - name: Install script again (check mode)
+ win_psscript:
+ name: "{{ script }}"
+ scope: "{{ scope }}"
+ repository: "{{ expected.repo }}"
+ register: result
+ check_mode: True
+
+ - name: Assert task is not changed (check mode)
+ assert:
+ that: result is not changed
+
+- name: Exact Version Tests
+ tags:
+ - exact
+ vars:
+ script: Test-Two
+ scope: current_user
+ expected:
+ repo: Repo2
+ version: "{{ earliest_version }}"
+ block:
+ - name: Install a script (check mode)
+ win_psscript:
+ name: "{{ script }}"
+ scope: "{{ scope }}"
+ required_version: "{{ expected.version }}"
+ register: result
+ check_mode: True
+
+ - name: Assert task is changed (check mode)
+ assert:
+ that: result is changed
+
+ - import_tasks: script_info.yml
+
+ - name: Ensure nothing was installed (check mode)
+ assert:
+ that:
+ - script not in scripts
+
+ - name: Install a script
+ win_psscript:
+ name: "{{ script }}"
+ scope: "{{ scope }}"
+ required_version: "{{ expected.version }}"
+ register: result
+ notify: Clear Installed Scripts
+
+ - name: Assert task is changed
+ assert:
+ that: result is changed
+
+ - import_tasks: script_info.yml
+
+ - name: Ensure script was installed
+ assert:
+ that:
+ - script in scripts
+ - scripts[script].Version is version(expected.version, '==')
+ - scripts[script].Repository == expected.repo
+ - scripts[script][scope]
+
+ - name: Install script again (check mode)
+ win_psscript:
+ name: "{{ script }}"
+ scope: "{{ scope }}"
+ required_version: "{{ expected.version }}"
+ register: result
+ check_mode: True
+
+ - name: Assert task is not changed (check mode)
+ assert:
+ that: result is not changed
+
+- name: Minimum / Maximum Version Tests
+ tags:
+ - minmax
+ - present
+ vars:
+ script: Test-Two
+ scope: current_user
+ minver: 1.0.1
+ maxver: 2.0.0
+ expected:
+ repo: Repo2
+ version: "1.0.10"
+ block:
+ - name: Install a script (check mode)
+ win_psscript:
+ name: "{{ script }}"
+ scope: "{{ scope }}"
+ minimum_version: "{{ minver }}"
+ maximum_version: "{{ maxver }}"
+ register: result
+ check_mode: True
+
+ - name: Assert task is changed (check mode)
+ assert:
+ that: result is changed
+
+ - import_tasks: script_info.yml
+
+ - name: Ensure nothing was installed (check mode)
+ assert:
+ that:
+ - script not in scripts or scripts[script].Version is version(expected.version, '<')
+
+ - name: Install a script
+ win_psscript:
+ name: "{{ script }}"
+ scope: "{{ scope }}"
+ minimum_version: "{{ minver }}"
+ maximum_version: "{{ maxver }}"
+ register: result
+ notify: Clear Installed Scripts
+
+ - name: Assert task is changed
+ assert:
+ that: result is changed
+
+ - import_tasks: script_info.yml
+
+ - name: Ensure script was installed
+ assert:
+ that:
+ - script in scripts
+ - scripts[script].Version is version(expected.version, '==')
+ - scripts[script].Repository == expected.repo
+ - scripts[script][scope]
+
+ - name: Install script again (check mode)
+ win_psscript:
+ name: "{{ script }}"
+ scope: "{{ scope }}"
+ minimum_version: "{{ minver }}"
+ maximum_version: "{{ maxver }}"
+ register: result
+ check_mode: True
+
+ - name: Assert task is not changed (check mode)
+ assert:
+ that: result is not changed
+
+- name: State Present Tests
+ tags:
+ - present
+ vars:
+ script: Test-Two
+ state: present
+ scope: all_users # implied
+ curver: 1.0.10
+ expected:
+ repo: Repo2
+ version: "{{ curver }}"
+ block:
+ - name: Install present script (check mode)
+ win_psscript:
+ name: "{{ script }}"
+ state: "{{ state }}"
+ register: result
+ check_mode: True
+
+ - name: Assert task is not changed (check mode)
+ assert:
+ that: result is not changed
+
+ - import_tasks: script_info.yml
+
+ - name: Ensure nothing was installed (check mode)
+ assert:
+ that:
+ - script in scripts
+ - scripts[script].Version is version(expected.version, '==')
+ - scripts[script].Repository == expected.repo
+
+ - name: Install present script
+ win_psscript:
+ name: "{{ script }}"
+ state: "{{ state }}"
+ register: result
+ notify: Clear Installed Scripts
+
+ - name: Assert task is not changed
+ assert:
+ that: result is not changed
+
+ - import_tasks: script_info.yml
+
+ - name: Ensure script was not installed
+ assert:
+ that:
+ - script in scripts
+ - scripts[script].Version is version(expected.version, '==')
+ - scripts[script].Repository == expected.repo
+
+- name: State Latest Tests
+ tags:
+ - latest
+ vars:
+ script: Test-Two
+ state: latest
+ scope: all_users # implied
+ expected:
+ repo: Repo2
+ version: "10.0.10"
+ block:
+ - name: Install latest script (check mode)
+ win_psscript:
+ name: "{{ script }}"
+ state: "{{ state }}"
+ register: result
+ check_mode: True
+
+ - name: Assert task is changed (check mode)
+ assert:
+ that: result is changed
+
+ - import_tasks: script_info.yml
+
+ - name: Ensure nothing was installed (check mode)
+ assert:
+ that:
+ - script not in scripts or scripts[script].Version is version(expected.version, '<')
+
+ - name: Install latest script
+ win_psscript:
+ name: "{{ script }}"
+ state: "{{ state }}"
+ register: result
+ notify: Clear Installed Scripts
+
+ - name: Assert task is changed
+ assert:
+ that: result is changed
+
+ - import_tasks: script_info.yml
+
+ - name: Ensure script was installed
+ assert:
+ that:
+ - script in scripts
+ - scripts[script].Version is version(expected.version, '==')
+ - scripts[script].Repository == expected.repo
+ - scripts[script][scope]
+
+ - name: Install latest script again (check mode)
+ win_psscript:
+ name: "{{ script }}"
+ state: "{{ state }}"
+ register: result
+ check_mode: True
+
+ - name: Assert task is not changed (check mode)
+ assert:
+ that: result is not changed
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psscript_info/aliases b/ansible_collections/community/windows/tests/integration/targets/win_psscript_info/aliases
new file mode 100644
index 000000000..3cf5b97e8
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psscript_info/aliases
@@ -0,0 +1 @@
+shippable/windows/group3
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psscript_info/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_psscript_info/defaults/main.yml
new file mode 100644
index 000000000..786fb5477
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psscript_info/defaults/main.yml
@@ -0,0 +1,34 @@
+---
+run_check_mode: False
+suffix: "{{ '(check mode)' if run_check_mode else '' }}"
+repository_name: Repo
+repo_path: "{{ remote_tmp_dir }}\\repo\\"
+
+sample_scripts:
+ - Test-RPC
+ - Upgrade-PowerShell
+ - Install-WMF3Hotfix
+ - Install-Git
+
+expected_fields:
+ - name
+ - version
+ - installed_location
+ - author
+ - copyright
+ - company_name
+ - description
+ - dependencies
+ - icon_uri
+ - license_uri
+ - project_uri
+ - repository_source_location
+ - repository
+ - release_notes
+ - installed_date
+ - published_date
+ - updated_date
+ - package_management_provider
+ - tags
+ - power_shell_get_format_version
+ - additional_metadata
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psscript_info/files/install-git.1.0.5.nupkg b/ansible_collections/community/windows/tests/integration/targets/win_psscript_info/files/install-git.1.0.5.nupkg
new file mode 100644
index 000000000..0dc10a004
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psscript_info/files/install-git.1.0.5.nupkg
Binary files differ
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psscript_info/files/install-wmf3hotfix.1.0.0.nupkg b/ansible_collections/community/windows/tests/integration/targets/win_psscript_info/files/install-wmf3hotfix.1.0.0.nupkg
new file mode 100644
index 000000000..2728fb4d5
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psscript_info/files/install-wmf3hotfix.1.0.0.nupkg
Binary files differ
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psscript_info/files/test-rpc.1.0.0.nupkg b/ansible_collections/community/windows/tests/integration/targets/win_psscript_info/files/test-rpc.1.0.0.nupkg
new file mode 100644
index 000000000..caf11314f
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psscript_info/files/test-rpc.1.0.0.nupkg
Binary files differ
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psscript_info/files/upgrade-powershell.1.0.0.nupkg b/ansible_collections/community/windows/tests/integration/targets/win_psscript_info/files/upgrade-powershell.1.0.0.nupkg
new file mode 100644
index 000000000..d260004a2
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psscript_info/files/upgrade-powershell.1.0.0.nupkg
Binary files differ
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psscript_info/meta/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_psscript_info/meta/main.yml
new file mode 100644
index 000000000..acc7fbcae
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psscript_info/meta/main.yml
@@ -0,0 +1,3 @@
+dependencies:
+ - setup_remote_tmp_dir
+ - setup_win_psget
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psscript_info/tasks/common.yml b/ansible_collections/community/windows/tests/integration/targets/win_psscript_info/tasks/common.yml
new file mode 100644
index 000000000..b4cdda063
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psscript_info/tasks/common.yml
@@ -0,0 +1,37 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2020, Brian Scholer <@briantist>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: Assert that the correct structure is returned {{ suffix }}
+ assert:
+ that:
+ - script_info.scripts is defined
+ - script_info.scripts is sequence()
+ quiet: yes
+
+- name: Assert that the correct number of scripts are returned {{ suffix }}
+ assert:
+ that: script_info.scripts | length >= expected_scripts | length
+ fail_msg: >-
+ Expected {{ expected_scripts | length }} scripts, got {{ script_info.scripts | map(attribute='name') | join(',') }} ({{ script_info.scripts | length}})
+ quiet: yes
+
+- name: Assert that all expected scripts are present {{ suffix }}
+ assert:
+ that: item in (script_info.scripts | map(attribute='name'))
+ fail_msg: "Expected script '{{ item }}' not found in results."
+ quiet: yes
+ loop: "{{ expected_scripts }}"
+ loop_control:
+ label: "Assert '{{ item }}' in result."
+
+- include_tasks: contains_all_fields.yml
+ vars:
+ dict_to_check: "{{ item }}"
+ loop: "{{
+ only_check_first
+ | default(True)
+ | bool
+ | ternary([ script_info.scripts[0] ], script_info.scripts)
+ }}"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psscript_info/tasks/contains_all_fields.yml b/ansible_collections/community/windows/tests/integration/targets/win_psscript_info/tasks/contains_all_fields.yml
new file mode 100644
index 000000000..20750e003
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psscript_info/tasks/contains_all_fields.yml
@@ -0,0 +1,13 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2020, Brian Scholer <@briantist>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: Check for key ('{{ key }}') in result
+ assert:
+ that: key in dict_to_check
+ quiet: yes
+ fail_msg: "'{{ key }}' not found in dict."
+ loop_control:
+ loop_var: key
+ loop: "{{ expected_fields }}"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psscript_info/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_psscript_info/tasks/main.yml
new file mode 100644
index 000000000..b3f1394e5
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psscript_info/tasks/main.yml
@@ -0,0 +1,49 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2020, Brian Scholer <@briantist>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: Reset repositories
+ ansible.windows.win_shell: |
+ Get-PSRepository | Unregister-PSRepository
+ Register-PSRepository -Default
+
+- name: Set up directory repository
+ ansible.windows.win_copy:
+ src: "{{ role_path }}/files/"
+ dest: "{{ repo_path }}"
+ force: no
+
+- name: Register repository
+ community.windows.win_psrepository:
+ name: "{{ repository_name }}"
+ source_location: "{{ repo_path }}"
+ installation_policy: trusted
+
+- block:
+ - name: Install Scripts
+ community.windows.win_psscript:
+ name: "{{ item }}"
+ state: latest
+ repository: "{{ repository_name }}"
+ loop: "{{ sample_scripts }}"
+
+ - name: Run Tests
+ import_tasks: tests.yml
+
+ - name: Run Tests (check mode)
+ import_tasks: tests.yml
+ vars:
+ run_check_mode: True
+
+ always:
+ - name: Remove Scripts
+ community.windows.win_psscript:
+ name: "{{ item }}"
+ state: absent
+ loop: "{{ sample_scripts }}"
+
+ - name: Reset repositories
+ ansible.windows.win_shell: |
+ Get-PSRepository | Unregister-PSRepository
+ Register-PSRepository -Default
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psscript_info/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_psscript_info/tasks/tests.yml
new file mode 100644
index 000000000..45931c567
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psscript_info/tasks/tests.yml
@@ -0,0 +1,92 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2020, Brian Scholer <@briantist>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: Get info on a named script
+ vars:
+ expected_scripts:
+ - "{{ sample_scripts[0] }}"
+ block:
+ - name: Get single script {{ suffix }}
+ community.windows.win_psscript_info:
+ name: "{{ expected_scripts[0] }}"
+ register: script_info
+
+ - include_tasks: common.yml
+
+ # block
+ check_mode: "{{ run_check_mode }}"
+
+- name: Get info on scripts by wildcard match
+ vars:
+ wildcard: "Install-*"
+ expected_scripts: "{{
+ sample_scripts
+ | select('match', '^Install-')
+ | list
+ }}"
+ block:
+ - name: Get multiple scripts by wildcard {{ suffix }}
+ community.windows.win_psscript_info:
+ name: "{{ wildcard }}"
+ register: script_info
+
+ - include_tasks: common.yml
+
+ # block
+ check_mode: "{{ run_check_mode }}"
+
+- name: Get info on scripts by repository
+ vars:
+ repository: "{{ repository_name }}"
+ expected_scripts: "{{ sample_scripts }}"
+ block:
+ - name: Get multiple scripts by repository {{ suffix }}
+ community.windows.win_psscript_info:
+ repository: "{{ repository }}"
+ register: script_info
+
+ - include_tasks: common.yml
+
+ # block
+ check_mode: "{{ run_check_mode }}"
+
+- name: Get info on scripts by repository and name pattern
+ vars:
+ wildcard: "*RPC"
+ repository: "{{ repository_name }}"
+ expected_scripts: "{{
+ sample_scripts
+ | select('match', 'RPC$')
+ | list
+ }}"
+ block:
+ - name: Get scripts by wildcard and repository {{ suffix }}
+ community.windows.win_psscript_info:
+ name: "{{ wildcard }}"
+ repository: "{{ repository }}"
+ register: script_info
+
+ - include_tasks: common.yml
+
+ # block
+ check_mode: "{{ run_check_mode }}"
+
+- name: Get info on all scripts
+ vars:
+ expected_scripts: "{{ sample_scripts }}"
+ block:
+ - name: Get all scripts {{ suffix }}
+ community.windows.win_psscript_info:
+ register: script_info
+
+ - include_tasks: common.yml
+
+ # one last time checking all the fields
+ - include_tasks: common.yml
+ vars:
+ only_check_first: False
+
+ # block
+ check_mode: "{{ run_check_mode }}"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_pssession_configuration/aliases b/ansible_collections/community/windows/tests/integration/targets/win_pssession_configuration/aliases
new file mode 100644
index 000000000..3cf5b97e8
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_pssession_configuration/aliases
@@ -0,0 +1 @@
+shippable/windows/group3
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_pssession_configuration/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_pssession_configuration/defaults/main.yml
new file mode 100644
index 000000000..3a6642d34
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_pssession_configuration/defaults/main.yml
@@ -0,0 +1,3 @@
+---
+config_name: Test
+config_description: A config for testing
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_pssession_configuration/meta/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_pssession_configuration/meta/main.yml
new file mode 100644
index 000000000..5648cebe8
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_pssession_configuration/meta/main.yml
@@ -0,0 +1,2 @@
+dependencies:
+ # - setup_remote_tmp_dir
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_pssession_configuration/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_pssession_configuration/tasks/main.yml
new file mode 100644
index 000000000..a56930b5d
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_pssession_configuration/tasks/main.yml
@@ -0,0 +1,21 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2020, Brian Scholer <@briantist>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- block:
+ - ansible.windows.setup:
+ gather_subset:
+ - '!all'
+ - '!min'
+ - powershell_version
+
+ - import_tasks: tests.yml
+
+ always:
+ - name: Remove
+ ansible.windows.win_shell: |
+ Unregister-PSSessionConfiguration -Name '{{ config_name }}' -Force -ErrorAction SilentlyContinue
+ ignore_errors: yes
+ # sometimes this fails because the connection was interrupted
+ # it doesn't matter because it's still successful
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_pssession_configuration/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_pssession_configuration/tasks/tests.yml
new file mode 100644
index 000000000..23e62164f
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_pssession_configuration/tasks/tests.yml
@@ -0,0 +1,448 @@
+# This file is part of Ansible
+
+# Copyright: (c) 2020, Brian Scholer <@briantist>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: Create a simple configuration (check)
+ win_pssession_configuration:
+ name: "{{ config_name }}"
+ description: "{{ config_description }}"
+ modules_to_import: Microsoft.PowerShell.Utility
+ register: status
+ check_mode: yes
+
+- name: Check for changed status
+ assert:
+ that: status is changed
+ quiet: yes
+
+- name: Create a simple configuration
+ win_pssession_configuration:
+ name: "{{ config_name }}"
+ description: "{{ config_description }}"
+ modules_to_import: Microsoft.PowerShell.Utility
+ register: status
+
+- name: Check for changed status
+ assert:
+ that: status is changed
+ quiet: yes
+
+- name: Create a simple configuration again (check)
+ win_pssession_configuration:
+ name: "{{ config_name }}"
+ description: "{{ config_description }}"
+ modules_to_import: Microsoft.PowerShell.Utility
+ register: status
+ check_mode: yes
+
+- name: Check for unchanged status
+ assert:
+ that: status is not changed
+ quiet: yes
+
+- name: Create a simple configuration again
+ win_pssession_configuration:
+ name: "{{ config_name }}"
+ description: "{{ config_description }}"
+ modules_to_import: Microsoft.PowerShell.Utility
+ register: status
+
+- name: Check for unchanged status
+ assert:
+ that: status is not changed
+ quiet: yes
+
+#######
+
+- name: Try to disable polling (failure expected)
+ win_pssession_configuration:
+ name: "{{ config_name }}"
+ description: "{{ config_description }}~~~~"
+ modules_to_import: Microsoft.PowerShell.Utility
+ async_timeout: 500
+ async_poll: 0
+ register: status
+ ignore_errors: yes
+
+- name: Ensure it failed
+ assert:
+ that:
+ - status is failed
+ - status.msg is search('async_poll')
+ quiet: yes
+
+- name: Try it with the keywords (failure expected)
+ win_pssession_configuration:
+ name: "{{ config_name }}"
+ description: "{{ config_description }}"
+ modules_to_import: Microsoft.PowerShell.Utility
+ async: 500
+ poll: 2
+ register: status
+ ignore_errors: yes
+
+- name: Check for expected failire
+ assert:
+ that: status is failed
+ quiet: yes
+
+#######
+
+- name: Try to set a parameter that's only available in PowerShell 5+ (check)
+ win_pssession_configuration:
+ name: "{{ config_name }}"
+ description: "{{ config_description }}"
+ mount_user_drive: True
+ register: status
+ check_mode: yes
+ ignore_errors: yes
+
+- name: Check for version-based status
+ assert:
+ that: (status is failed) == (ansible_powershell_version < 5)
+ quiet: yes
+
+#######
+# Incomplete tests for future enhancement of waiting for connections before making changes
+
+# - name: Start a 45 second WinRM connection
+# ansible.windows.win_shell: |
+# Invoke-Command -ComputerName . -ScriptBlock { Start-Sleep -Seconds 45 } -AsJob
+
+# - name: Make a change with a 10 second fail on timeout (failure expected)
+# win_pssession_configuration:
+# name: "{{ config_name }}"
+# description: "{{ config_description }}"
+# mount_user_drive: False
+# existing_connection_timeout_seconds: 10
+# existing_connection_timeout_action: fail
+# register: status
+# ignore_errors: yes
+
+# - name: Check for failed status
+# assert:
+# that: status is failed
+# quiet: yes
+
+# - name: Start a 25 second WinRM connection
+# ansible.windows.win_shell: |
+# Invoke-Command -ComputerName . -ScriptBlock { Start-Sleep -Seconds 25 } -AsJob
+
+# - name: Make a change with a 45 second fail on timeout (success expected)
+# win_pssession_configuration:
+# name: "{{ config_name }}"
+# description: "{{ config_description }}"
+# mount_user_drive: False
+# existing_connection_timeout_seconds: 10
+# existing_connection_timeout_action: fail
+# register: status
+
+# - name: Check for changed status
+# assert:
+# that: status is changed
+# quiet: yes
+
+#######
+- name: Omit a field that doesn't matter (check)
+ win_pssession_configuration:
+ name: "{{ config_name }}"
+ # description: "{{ config_description }}" # intentionally omitted
+ modules_to_import: Microsoft.PowerShell.Utility
+ register: status
+ check_mode: yes
+
+- name: Check for unchanged status
+ assert:
+ that: status is not changed
+ quiet: yes
+
+- name: Omit a field that doesn't matter
+ win_pssession_configuration:
+ name: "{{ config_name }}"
+ # description: "{{ config_description }}" # intentionally omitted
+ modules_to_import: Microsoft.PowerShell.Utility
+ register: status
+
+- name: Check for unchanged status
+ assert:
+ that: status is not changed
+ quiet: yes
+
+#######
+
+- name: Omit a field that doesn't matter by default but does explicitly (check)
+ win_pssession_configuration:
+ name: "{{ config_name }}"
+ # description: "{{ config_description }}" # intentionally omitted
+ modules_to_import: Microsoft.PowerShell.Utility
+ lenient_config_fields:
+ - guid
+ - author
+ register: status
+ check_mode: yes
+
+- name: Check for changed status
+ assert:
+ that: status is changed
+ quiet: yes
+
+- name: Omit a field that doesn't matter by default but does explicitly
+ win_pssession_configuration:
+ name: "{{ config_name }}"
+ # description: "{{ config_description }}" # intentionally omitted
+ modules_to_import: Microsoft.PowerShell.Utility
+ lenient_config_fields:
+ - guid
+ - author
+ register: status
+
+- name: Check for changed status
+ assert:
+ that: status is changed
+ quiet: yes
+
+########
+
+- name: Change something not in the config file (check)
+ win_pssession_configuration:
+ name: "{{ config_name }}"
+ thread_options: reuse_thread
+ use_shared_process: True
+ register: status
+ check_mode: yes
+
+- name: Check for changed status
+ assert:
+ that: status is changed
+ quiet: yes
+
+- name: Change something not in the config file
+ win_pssession_configuration:
+ name: "{{ config_name }}"
+ thread_options: reuse_thread
+ use_shared_process: True
+ register: status
+
+- name: Check for changed status
+ assert:
+ that: status is changed
+ quiet: yes
+
+- name: Change something not in the config file (again) (check)
+ win_pssession_configuration:
+ name: "{{ config_name }}"
+ thread_options: reuse_thread
+ use_shared_process: True
+ register: status
+ check_mode: yes
+
+- name: Check for unchanged status
+ assert:
+ that: status is not changed
+ quiet: yes
+
+- name: Change something not in the config file (again)
+ win_pssession_configuration:
+ name: "{{ config_name }}"
+ thread_options: reuse_thread
+ use_shared_process: True
+ register: status
+
+- name: Check for unchanged status
+ assert:
+ that: status is not changed
+ quiet: yes
+
+######
+
+- name: Check custom type parameters for PowerShell <= 4 (check)
+ win_pssession_configuration:
+ name: "{{ config_name }}"
+ guid: "{{ 'test' | to_uuid }}"
+ powershell_version: '3.0'
+ maximum_received_data_size_per_command_mb: 5.0E+11
+ maximum_received_object_size_mb: 6.6666666666666666666666666
+ register: status
+ when: ansible_powershell_version <= 4
+
+- name: Check custom type parameters for PowerShell >= 5 (check)
+ win_pssession_configuration:
+ name: "{{ config_name }}"
+ guid: "{{ 'test' | to_uuid }}"
+ powershell_version: '3.0'
+ user_drive_maximum_size: 5000000000
+ maximum_received_data_size_per_command_mb: 5.0E+11
+ maximum_received_object_size_mb: 6.6666666666666666666666666
+ register: status
+ when: ansible_powershell_version >= 5
+
+######
+
+- name: Reset back to a steady state
+ win_pssession_configuration:
+ name: "{{ config_name }}"
+ register: status
+
+- name: Check for changed status
+ assert:
+ that: status is changed
+ quiet: yes
+ ignore_errors: yes
+
+- name: Reset back to a steady state (again)
+ win_pssession_configuration:
+ name: "{{ config_name }}"
+ register: status
+
+- name: Check for unchanged status
+ assert:
+ that: status is not changed
+ quiet: yes
+ ignore_errors: yes
+
+#######
+
+- name: "RunAs Tests"
+ vars:
+ runas_user: "{{ ansible_user }}"
+ runas_pass: "{{ ansible_password }}"
+ block:
+ - name: Change runas credential (check)
+ win_pssession_configuration:
+ name: "{{ config_name }}"
+ run_as_credential_username: "{{ runas_user }}"
+ run_as_credential_password: "{{ runas_pass }}"
+ register: status
+ check_mode: yes
+
+ - name: Check for changed status
+ assert:
+ that: status is changed
+ quiet: yes
+
+ - name: Change runas credential
+ win_pssession_configuration:
+ name: "{{ config_name }}"
+ run_as_credential_username: "{{ runas_user }}"
+ run_as_credential_password: "{{ runas_pass }}"
+ register: status
+
+ - name: Check for changed status
+ assert:
+ that: status is changed
+ quiet: yes
+
+ - name: Try an invalid runas credential (failure expected)
+ win_pssession_configuration:
+ name: "{{ config_name }}"
+ run_as_credential_username: Fake
+ run_as_credential_password: Fake
+ register: status
+ ignore_errors: yes
+
+ - name: Check for failed status
+ assert:
+ that: status is failed
+ quiet: yes
+
+ - name: Ensure the sessions configuration still exists with the working user
+ ansible.windows.win_shell: |
+ $sc = Get-PSSessionConfiguration -Name '{{ config_name }}'
+ if ($sc.RunAsUser -ne '{{ runas_user }}') {
+ throw
+ }
+ register: status
+
+#######
+
+- name: complex configuration for pwsh 5.1+
+ when: ansible_powershell_version > 4
+ block:
+ - name: Create a complex configuration
+ win_pssession_configuration:
+ name: "{{ config_name }}"
+ description: "{{ config_description }}"
+ modules_to_import: Microsoft.PowerShell.Utility
+ visible_aliases: []
+ visible_cmdlets: []
+ visible_external_commands: []
+ visible_functions: []
+ security_descriptor_sddl: "O:NSG:BAD:P(A;;GA;;;IU)(A;;GA;;;BA)(A;;GA;;;RM)S:P(AU;FA;GA;;;WD)(AU;SA;GXGW;;;WD)"
+ register: status
+
+ - name: Check for changed status
+ assert:
+ that: status is changed
+ quiet: yes
+
+ - name: Create a complex configuration again (check)
+ win_pssession_configuration:
+ name: "{{ config_name }}"
+ description: "{{ config_description }}"
+ modules_to_import: Microsoft.PowerShell.Utility
+ visible_aliases: []
+ visible_cmdlets: []
+ visible_external_commands: []
+ visible_functions: []
+ security_descriptor_sddl: "O:NSG:BAD:P(A;;GA;;;IU)(A;;GA;;;BA)(A;;GA;;;RM)S:P(AU;FA;GA;;;WD)(AU;SA;GXGW;;;WD)"
+ register: status
+ check_mode: yes
+
+ - name: Check for unchanged status
+ assert:
+ that: status is not changed
+ quiet: yes
+
+ - name: Create a complex configuration again
+ win_pssession_configuration:
+ name: "{{ config_name }}"
+ description: "{{ config_description }}"
+ modules_to_import: Microsoft.PowerShell.Utility
+ visible_aliases: []
+ visible_cmdlets: []
+ visible_external_commands: []
+ visible_functions: []
+ security_descriptor_sddl: "O:NSG:BAD:P(A;;GA;;;IU)(A;;GA;;;BA)(A;;GA;;;RM)S:P(AU;FA;GA;;;WD)(AU;SA;GXGW;;;WD)"
+ register: status
+
+ - name: Check for unchanged status
+ assert:
+ that: status is not changed
+ quiet: yes
+
+#######
+
+- name: Test session configuration removal (check)
+ win_pssession_configuration:
+ name: "{{ config_name }}"
+ state: absent
+ register: status
+ check_mode: yes
+
+- name: Check for changed status
+ assert:
+ that: status is changed
+ quiet: yes
+
+- name: Test session configuration removal
+ win_pssession_configuration:
+ name: "{{ config_name }}"
+ state: absent
+ register: status
+
+- name: Check for changed status
+ assert:
+ that: status is changed
+ quiet: yes
+
+- name: Test session configuration removal (again)
+ win_pssession_configuration:
+ name: "{{ config_name }}"
+ state: absent
+ register: status
+
+- name: Check for unchanged status
+ assert:
+ that: status is not changed
+ quiet: yes
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_rabbitmq_plugin/aliases b/ansible_collections/community/windows/tests/integration/targets/win_rabbitmq_plugin/aliases
new file mode 100644
index 000000000..aefcbeb1b
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_rabbitmq_plugin/aliases
@@ -0,0 +1,2 @@
+shippable/windows/group3
+disabled
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_rabbitmq_plugin/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_rabbitmq_plugin/tasks/main.yml
new file mode 100644
index 000000000..ce60dd109
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_rabbitmq_plugin/tasks/main.yml
@@ -0,0 +1,7 @@
+# Setup action creates ansible_distribution_version variable
+- ansible.windows.setup:
+
+- include_tasks: tasks/tests.yml
+ # Works on windows >= Windows 7/Windows Server 2008 R2
+ # See https://github.com/ansible/ansible/pull/28118#issuecomment-323684042 for additional info.
+ when: ansible_distribution_version is version('6.1', '>=')
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_rabbitmq_plugin/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_rabbitmq_plugin/tasks/tests.yml
new file mode 100644
index 000000000..53ee0efdf
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_rabbitmq_plugin/tasks/tests.yml
@@ -0,0 +1,134 @@
+- name: Ensure RabbitMQ installed
+ chocolatey.chocolatey.win_chocolatey:
+ name: rabbitmq
+ state: present
+
+- name: Ensure that rabbitmq_management plugin disabled
+ win_rabbitmq_plugin:
+ names: rabbitmq_management
+ state: disabled
+
+- name: Enable rabbitmq_management plugin in check mode
+ win_rabbitmq_plugin:
+ names: rabbitmq_management
+ state: enabled
+ check_mode: yes
+ register: enable_plugin_in_check_mode
+
+- name: Check that enabling plugin in check mode succeeds with a change
+ assert:
+ that:
+ - enable_plugin_in_check_mode.changed == true
+
+- name: Enable rabbitmq_management plugin in check mode again
+ win_rabbitmq_plugin:
+ names: rabbitmq_management
+ state: enabled
+ check_mode: yes
+ register: enable_plugin_in_check_mode_again
+
+- name: Check that enabling plugin in check mode does not make changes
+ assert:
+ that:
+ - enable_plugin_in_check_mode_again.changed == true
+
+- name: Enable rabbitmq_management plugin
+ win_rabbitmq_plugin:
+ names: rabbitmq_management
+ state: enabled
+ register: enable_plugin
+
+- name: Check that enabling plugin succeeds with a change
+ assert:
+ that:
+ - enable_plugin.changed == true
+ - enable_plugin.enabled == ['rabbitmq_management']
+
+- name: Enable enabled rabbitmq_management plugin
+ win_rabbitmq_plugin:
+ names: rabbitmq_management
+ state: enabled
+ register: enable_plugin_again
+
+- name: Check that enabling enabled plugin succeeds without a change
+ assert:
+ that:
+ - enable_plugin_again.changed == false
+ - enable_plugin_again.enabled == []
+
+- name: Enable new plugin when 'new_only' option is 'no' (by default) and there are installed plugins
+ win_rabbitmq_plugin:
+ names: rabbitmq_mqtt
+ state: enabled
+ check_mode: yes
+ register: enable_plugin_without_new_only
+
+- name: Check that 'new_only == no' option enables new plugin and disables the old one
+ assert:
+ that:
+ - enable_plugin_without_new_only.changed == true
+ - enable_plugin_without_new_only.enabled == ['rabbitmq_mqtt']
+ - enable_plugin_without_new_only.disabled == ['rabbitmq_management']
+
+- name: Enable new plugin when 'new_only' option is 'yes' and there are installed plugins
+ win_rabbitmq_plugin:
+ names: rabbitmq_mqtt
+ state: enabled
+ new_only: yes
+ check_mode: yes
+ register: enable_plugin_with_new_only
+
+- name: Check that 'new_only == yes' option just enables new plugin
+ assert:
+ that:
+ - enable_plugin_with_new_only.changed == true
+ - enable_plugin_with_new_only.enabled == ['rabbitmq_mqtt']
+ - enable_plugin_with_new_only.disabled == []
+
+- name: Disable rabbitmq_management plugin in check mode
+ win_rabbitmq_plugin:
+ names: rabbitmq_management
+ state: disabled
+ check_mode: yes
+ register: disable_plugin_in_check_mode
+
+- name: Check that disabling plugin in check mode succeeds with a change
+ assert:
+ that:
+ - disable_plugin_in_check_mode.changed == true
+
+- name: Disable rabbitmq_management plugin in check mode again
+ win_rabbitmq_plugin:
+ names: rabbitmq_management
+ state: disabled
+ check_mode: yes
+ register: disable_plugin_in_check_mode_again
+
+- name: Check that disabling plugin in check mode does not make changes
+ assert:
+ that:
+ - disable_plugin_in_check_mode_again.changed == true
+
+- name: Disable rabbitmq_management plugin
+ win_rabbitmq_plugin:
+ names: rabbitmq_management
+ state: disabled
+ register: disable_plugin
+
+- name: Check that disabling plugin succeeds with a change
+ assert:
+ that:
+ - disable_plugin.changed == true
+ - disable_plugin.disabled == ['rabbitmq_management']
+
+- name: Disable disabled rabbitmq_management plugin
+ win_rabbitmq_plugin:
+ names: rabbitmq_management
+ state: disabled
+ register: disable_plugin_again
+
+- name: Check that disabling disabled plugin succeeds without a change
+ assert:
+ that:
+ - disable_plugin_again.changed == false
+ - disable_plugin_again.disabled == []
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_rds/aliases b/ansible_collections/community/windows/tests/integration/targets/win_rds/aliases
new file mode 100644
index 000000000..8d0a829ba
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_rds/aliases
@@ -0,0 +1,5 @@
+shippable/windows/group3
+destructive
+win_rds_cap
+win_rds_rap
+win_rds_settings
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_rds/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_rds/defaults/main.yml
new file mode 100644
index 000000000..a332469ea
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_rds/defaults/main.yml
@@ -0,0 +1,9 @@
+# win_rds_cap
+test_win_rds_cap_name: Ansible Test CAP
+
+# win_rds_rap
+test_win_rds_rap_name: Ansible Test RAP
+
+# win_rds_settings
+test_win_rds_settings_path: '{{ remote_tmp_dir }}\win_rds_settings'
+rds_cert_suject: rdg.test.com
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_rds/meta/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_rds/meta/main.yml
new file mode 100644
index 000000000..45806c8dc
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_rds/meta/main.yml
@@ -0,0 +1,2 @@
+dependencies:
+- setup_remote_tmp_dir \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_rds/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_rds/tasks/main.yml
new file mode 100644
index 000000000..25b32a553
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_rds/tasks/main.yml
@@ -0,0 +1,73 @@
+---
+# Cannot use win_feature to install RDS on Server 2008
+- name: check if feature is availble
+ ansible.windows.win_shell: if (Get-Command -Name Add-WindowsFeature -ErrorAction SilentlyContinue) { $true } else { $false }
+ changed_when: False
+ register: module_available
+
+- name: install Remote Desktop Gateway features
+ when: module_available.stdout | trim | bool
+ block:
+ - name: ensure Remote Desktop Gateway services are installed
+ ansible.windows.win_feature:
+ name:
+ - RDS-Gateway
+ - RDS-Licensing
+ - RDS-RD-Server
+ state: present
+ register: rds_install
+
+ - name: reboot server if needed
+ ansible.windows.win_reboot:
+ when: rds_install.reboot_required
+
+ # After a reboot Windows is still configuring the feature, this is a hack to wait until that is finished
+ - name: wait for component servicing to be finished
+ ansible.windows.win_shell: |
+ $start = Get-Date
+ $path = "HKLM:\SYSTEM\CurrentControlSet\Control\Winlogon\Notifications\Components\TrustedInstaller"
+ $tries = 0
+ while ((Get-ItemProperty -Path $path -Name Events).Events.Contains("CreateSession")) {
+ $tries += 1
+ Start-Sleep -Seconds 5
+ if (((Get-Date) - $start).TotalSeconds -gt 180) {
+ break
+ }
+ }
+ $tries
+ changed_when: False
+
+ - name: run win_rds_cap integration tests
+ include_tasks: win_rds_cap.yml
+
+ - name: run win_rds_rap integration tests
+ include_tasks: win_rds_rap.yml
+
+ - name: run win_rds_settings integration tests
+ include_tasks: win_rds_settings.yml
+
+ always:
+ # Server 2008 R2 requires us to remove this first before the other features
+ - name: remove the RDS-Gateway feature
+ ansible.windows.win_feature:
+ name: RDS-Gateway
+ state: absent
+ register: rds_uninstall
+
+ - name: reboot after removing RDS-Gateway feature
+ ansible.windows.win_reboot:
+ when: rds_uninstall.reboot_required
+
+ # Now remove the remaining features
+ - name: remove installed RDS feature
+ ansible.windows.win_feature:
+ name:
+ - RDS-Licensing
+ - RDS-RD-Server
+ - Web-Server # not part of the initial feature install but RDS-Gateway requires this and it breaks httptester
+ state: absent
+ register: rds_uninstall2
+
+ - name: reboot after feature removal
+ ansible.windows.win_reboot:
+ when: rds_uninstall2.reboot_required
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_rds/tasks/win_rds_cap.yml b/ansible_collections/community/windows/tests/integration/targets/win_rds/tasks/win_rds_cap.yml
new file mode 100644
index 000000000..24adb25b9
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_rds/tasks/win_rds_cap.yml
@@ -0,0 +1,9 @@
+---
+- name: run tests with cleanup
+ block:
+ - name: run tests
+ include_tasks: win_rds_cap_tests.yml
+
+ always:
+ - name: delete all CAPs
+ ansible.windows.win_shell: Import-Module RemoteDesktopServices; Remove-Item -Path RDS:\GatewayServer\CAP\* -Recurse
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_rds/tasks/win_rds_cap_tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_rds/tasks/win_rds_cap_tests.yml
new file mode 100644
index 000000000..a7dc059a2
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_rds/tasks/win_rds_cap_tests.yml
@@ -0,0 +1,264 @@
+---
+- name: test create a new CAP (check mode)
+ win_rds_cap:
+ name: '{{ test_win_rds_cap_name }}'
+ user_groups:
+ - administrators
+ - users@builtin
+ state: present
+ register: new_cap_check
+ check_mode: yes
+
+- name: get result of create a new CAP (check mode)
+ ansible.windows.win_shell: Import-Module RemoteDesktopServices; Write-Host (Test-Path "RDS:\GatewayServer\CAP\{{ test_win_rds_cap_name }}")
+ register: new_cap_actual_check
+
+- name: assert results of create a new CAP (check mode)
+ assert:
+ that:
+ - new_cap_check.changed == true
+ - new_cap_actual_check.stdout_lines[0] == "False"
+
+- name: test create a new CAP
+ win_rds_cap:
+ name: '{{ test_win_rds_cap_name }}'
+ user_groups:
+ - administrators
+ - users@builtin
+ state: present
+ register: new_cap
+
+- name: get result of create a new CAP
+ ansible.windows.win_shell: Import-Module RemoteDesktopServices; Write-Host (Test-Path "RDS:\GatewayServer\CAP\{{ test_win_rds_cap_name }}")
+ register: new_cap_actual
+
+- name: assert results of create a new CAP
+ assert:
+ that:
+ - new_cap.changed == true
+ - new_cap_actual.stdout_lines[0] == "True"
+
+- name: test create a new CAP (idempotent)
+ win_rds_cap:
+ name: '{{ test_win_rds_cap_name }}'
+ user_groups:
+ - administrators
+ - users@builtin
+ state: present
+ register: new_cap_again
+
+- name: get result of create a new CAP (idempotent)
+ ansible.windows.win_shell: Import-Module RemoteDesktopServices; Write-Host (Test-Path "RDS:\GatewayServer\CAP\{{ test_win_rds_cap_name }}")
+ register: new_cap_actual_again
+
+- name: assert results of create a new CAP (idempotent)
+ assert:
+ that:
+ - new_cap_again.changed == false
+ - new_cap_actual_again.stdout_lines[0] == "True"
+
+- name: test edit a CAP
+ win_rds_cap:
+ name: '{{ test_win_rds_cap_name }}'
+ user_groups:
+ # Test with different group name formats
+ - users@builtin
+ - .\guests
+ computer_groups:
+ - administrators
+ auth_method: both
+ session_timeout: 20
+ session_timeout_action: reauth
+ allow_only_sdrts_servers: true
+ idle_timeout: 10
+ redirect_clipboard: false
+ redirect_drives: false
+ redirect_printers: false
+ redirect_serial: false
+ redirect_pnp: false
+ state: disabled
+ register: edit_cap
+
+- name: get result of edit a CAP
+ ansible.windows.win_shell: |
+ Import-Module RemoteDesktopServices;
+ $cap_path = "RDS:\GatewayServer\CAP\{{ test_win_rds_cap_name }}"
+ $cap = @{}
+ Get-ChildItem -Path "$cap_path" | foreach { $cap.Add($_.Name,$_.CurrentValue) }
+ $cap.DeviceRedirection = @{}
+ Get-ChildItem -Path "$cap_path\DeviceRedirection" | foreach { $cap.DeviceRedirection.Add($_.Name, ($_.CurrentValue -eq 1)) }
+ $cap.UserGroups = @(Get-ChildItem -Path "$cap_path\UserGroups" | Select -ExpandProperty Name)
+ $cap.ComputerGroups = @(Get-ChildItem -Path "$cap_path\ComputerGroups" | Select -ExpandProperty Name)
+ $cap | ConvertTo-Json
+ register: edit_cap_actual_json
+
+- name: parse result of edit a CAP.
+ set_fact:
+ edit_cap_actual: '{{ edit_cap_actual_json.stdout | from_json }}'
+
+- name: assert results of edit a CAP
+ assert:
+ that:
+ - edit_cap.changed == true
+ - edit_cap_actual.Status == "0"
+ - edit_cap_actual.EvaluationOrder == "1"
+ - edit_cap_actual.AllowOnlySDRTSServers == "1"
+ - edit_cap_actual.AuthMethod == "3"
+ - edit_cap_actual.IdleTimeout == "10"
+ - edit_cap_actual.SessionTimeoutAction == "1"
+ - edit_cap_actual.SessionTimeout == "20"
+ - edit_cap_actual.DeviceRedirection.Clipboard == false
+ - edit_cap_actual.DeviceRedirection.DiskDrives == false
+ - edit_cap_actual.DeviceRedirection.PlugAndPlayDevices == false
+ - edit_cap_actual.DeviceRedirection.Printers == false
+ - edit_cap_actual.DeviceRedirection.SerialPorts == false
+ - edit_cap_actual.UserGroups | length == 2
+ - edit_cap_actual.UserGroups[0] == "Users@BUILTIN"
+ - edit_cap_actual.UserGroups[1] == "Guests@BUILTIN"
+ - edit_cap_actual.ComputerGroups | length == 1
+ - edit_cap_actual.ComputerGroups[0] == "Administrators@BUILTIN"
+
+- name: test remove all computer groups of CAP
+ win_rds_cap:
+ name: '{{ test_win_rds_cap_name }}'
+ computer_groups: []
+ register: remove_computer_groups_cap
+
+- name: get result of remove all computer groups of CAP
+ ansible.windows.win_shell: |
+ Import-Module RemoteDesktopServices;
+ $cap_path = "RDS:\GatewayServer\CAP\{{ test_win_rds_cap_name }}"
+ Write-Host @(Get-ChildItem -Path "$cap_path\ComputerGroups" | Select -ExpandProperty Name).Count
+ register: remove_computer_groups_cap_actual
+
+- name: assert results of remove all computer groups of CAP
+ assert:
+ that:
+ - remove_computer_groups_cap.changed == true
+ - remove_computer_groups_cap_actual.stdout_lines[0] == "0"
+
+- name: test create a CAP in second position
+ win_rds_cap:
+ name: '{{ test_win_rds_cap_name }} Second'
+ user_groups:
+ - users@builtin
+ order: 2
+ state: present
+ register: second_cap
+
+- name: get result of create a CAP in second position
+ ansible.windows.win_shell: Import-Module RemoteDesktopServices; Write-Host (Get-Item "RDS:\GatewayServer\CAP\{{ test_win_rds_cap_name }} Second\EvaluationOrder").CurrentValue
+ register: second_cap_actual
+
+- name: assert results of create a CAP in second position
+ assert:
+ that:
+ - second_cap.changed == true
+ - second_cap.warnings is not defined
+ - second_cap_actual.stdout_lines[0] == "2"
+
+- name: test create a CAP with order greater than existing CAP count
+ win_rds_cap:
+ name: '{{ test_win_rds_cap_name }} Last'
+ user_groups:
+ - users@builtin
+ order: 50
+ state: present
+ register: cap_big_order
+
+- name: get result of create a CAP with order greater than existing CAP count
+ ansible.windows.win_shell: Import-Module RemoteDesktopServices; Write-Host (Get-Item "RDS:\GatewayServer\CAP\{{ test_win_rds_cap_name }} Last\EvaluationOrder").CurrentValue
+ register: cap_big_order_actual
+
+- name: assert results of create a CAP with order greater than existing CAP count
+ assert:
+ that:
+ - cap_big_order.changed == true
+ - cap_big_order.warnings | length == 1
+ - cap_big_order_actual.stdout_lines[0] == "3"
+
+- name: test remove CAP (check mode)
+ win_rds_cap:
+ name: '{{ test_win_rds_cap_name }}'
+ state: absent
+ register: remove_cap_check
+ check_mode: yes
+
+- name: get result of remove CAP (check mode)
+ ansible.windows.win_shell: Import-Module RemoteDesktopServices; Write-Host (Test-Path "RDS:\GatewayServer\CAP\{{ test_win_rds_cap_name }}")
+ register: remove_cap_actual_check
+
+- name: assert results of remove CAP (check mode)
+ assert:
+ that:
+ - remove_cap_check.changed == true
+ - remove_cap_actual_check.stdout_lines[0] == "True"
+
+- name: test remove CAP
+ win_rds_cap:
+ name: '{{ test_win_rds_cap_name }}'
+ state: absent
+ register: remove_cap_check
+
+- name: get result of remove CAP
+ ansible.windows.win_shell: Import-Module RemoteDesktopServices; Write-Host (Test-Path "RDS:\GatewayServer\CAP\{{ test_win_rds_cap_name }}")
+ register: remove_cap_actual_check
+
+- name: assert results of remove CAP
+ assert:
+ that:
+ - remove_cap_check.changed == true
+ - remove_cap_actual_check.stdout_lines[0] == "False"
+
+- name: test remove CAP (idempotent)
+ win_rds_cap:
+ name: '{{ test_win_rds_cap_name }}'
+ state: absent
+ register: remove_cap_check
+
+- name: get result of remove CAP (idempotent)
+ ansible.windows.win_shell: Import-Module RemoteDesktopServices; Write-Host (Test-Path "RDS:\GatewayServer\CAP\{{ test_win_rds_cap_name }}")
+ register: remove_cap_actual_check
+
+- name: assert results of remove CAP (idempotent)
+ assert:
+ that:
+ - remove_cap_check.changed == false
+ - remove_cap_actual_check.stdout_lines[0] == "False"
+
+- name: fail when create a new CAP without user group
+ win_rds_cap:
+ name: '{{ test_win_rds_cap_name }}'
+ state: present
+ register: new_cap_without_group
+ check_mode: yes
+ failed_when: "new_cap_without_group.msg != 'User groups must be defined to create a new CAP.'"
+
+- name: fail when create a new CAP with an empty user group list
+ win_rds_cap:
+ name: '{{ test_win_rds_cap_name }}'
+ user_groups: []
+ state: present
+ register: new_cap_empty_group_list
+ check_mode: yes
+ failed_when: "new_cap_empty_group_list.msg is not search('cannot be an empty list')"
+
+- name: fail when create a new CAP with an invalid user group
+ win_rds_cap:
+ name: '{{ test_win_rds_cap_name }}'
+ user_groups:
+ - fake_group
+ state: present
+ register: new_cap_invalid_user_group
+ check_mode: yes
+ failed_when: new_cap_invalid_user_group.changed != false or new_cap_invalid_user_group.msg is not search('is not a valid account')
+
+- name: fail when create a new CAP with an invalid computer group
+ win_rds_cap:
+ name: '{{ test_win_rds_cap_name }}'
+ computer_groups:
+ - fake_group
+ state: present
+ register: new_cap_invalid_computer_group
+ check_mode: yes
+ failed_when: new_cap_invalid_computer_group.changed != false or new_cap_invalid_computer_group.msg is not search('is not a valid account')
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_rds/tasks/win_rds_rap.yml b/ansible_collections/community/windows/tests/integration/targets/win_rds/tasks/win_rds_rap.yml
new file mode 100644
index 000000000..774076269
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_rds/tasks/win_rds_rap.yml
@@ -0,0 +1,9 @@
+---
+- name: run tests with cleanup
+ block:
+ - name: run tests
+ include_tasks: win_rds_rap_tests.yml
+
+ always:
+ - name: delete all RAPs
+ ansible.windows.win_shell: Import-Module RemoteDesktopServices; Remove-Item -Path RDS:\GatewayServer\RAP\* -Recurse
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_rds/tasks/win_rds_rap_tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_rds/tasks/win_rds_rap_tests.yml
new file mode 100644
index 000000000..1e0fdbe03
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_rds/tasks/win_rds_rap_tests.yml
@@ -0,0 +1,254 @@
+---
+- name: test create a new RAP (check mode)
+ win_rds_rap:
+ name: '{{ test_win_rds_rap_name }}'
+ user_groups:
+ - administrators
+ - users@builtin
+ state: present
+ register: new_rap_check
+ check_mode: yes
+
+- name: get result of create a new RAP (check mode)
+ ansible.windows.win_shell: Import-Module RemoteDesktopServices; Write-Host (Test-Path "RDS:\GatewayServer\RAP\{{ test_win_rds_rap_name }}")
+ register: new_rap_actual_check
+
+- name: assert results of create a new RAP (check mode)
+ assert:
+ that:
+ - new_rap_check.changed == true
+ - new_rap_actual_check.stdout_lines[0] == "False"
+
+- name: test create a new RAP
+ win_rds_rap:
+ name: '{{ test_win_rds_rap_name }}'
+ user_groups:
+ - administrators
+ - users@builtin
+ state: present
+ register: new_rap
+
+- name: get result of create a new RAP
+ ansible.windows.win_shell: Import-Module RemoteDesktopServices; Write-Host (Test-Path "RDS:\GatewayServer\RAP\{{ test_win_rds_rap_name }}")
+ register: new_rap_actual
+
+- name: assert results of create a new RAP
+ assert:
+ that:
+ - new_rap.changed == true
+ - new_rap_actual.stdout_lines[0] == "True"
+
+- name: test create a new RAP (idempotent)
+ win_rds_rap:
+ name: '{{ test_win_rds_rap_name }}'
+ user_groups:
+ - administrators
+ - users@builtin
+ state: present
+ register: new_rap_again
+
+- name: get result of create a new RAP (idempotent)
+ ansible.windows.win_shell: Import-Module RemoteDesktopServices; Write-Host (Test-Path "RDS:\GatewayServer\RAP\{{ test_win_rds_rap_name }}")
+ register: new_rap_actual_again
+
+- name: assert results of create a new RAP (idempotent)
+ assert:
+ that:
+ - new_rap_again.changed == false
+ - new_rap_actual_again.stdout_lines[0] == "True"
+
+- name: test edit a RAP
+ win_rds_rap:
+ name: '{{ test_win_rds_rap_name }}'
+ description: 'Description of {{ test_win_rds_rap_name }}'
+ user_groups:
+ # Test with different group name formats
+ - users@builtin
+ - .\guests
+ computer_group_type: ad_network_resource_group
+ computer_group: administrators
+ allowed_ports:
+ - 3389
+ - 3390
+ - 3391
+ state: disabled
+ register: edit_rap
+
+- name: get result of edit a RAP
+ ansible.windows.win_shell: |
+ Import-Module RemoteDesktopServices;
+ $rap_path = "RDS:\GatewayServer\RAP\{{ test_win_rds_rap_name }}"
+ $rap = @{}
+ Get-ChildItem -Path "$rap_path" | foreach { $rap.Add($_.Name,$_.CurrentValue) }
+ $rap.UserGroups = @(Get-ChildItem -Path "$rap_path\UserGroups" | Select -ExpandProperty Name)
+ $rap | ConvertTo-Json
+ register: edit_rap_actual_json
+
+- name: parse result of edit a RAP.
+ set_fact:
+ edit_rap_actual: '{{ edit_rap_actual_json.stdout | from_json }}'
+
+- name: assert results of edit a RAP
+ assert:
+ that:
+ - edit_rap.changed == true
+ - edit_rap_actual.Status == "0"
+ - edit_rap_actual.Description == "Description of {{ test_win_rds_rap_name }}"
+ - edit_rap_actual.PortNumbers == "3389,3390,3391"
+ - edit_rap_actual.UserGroups | length == 2
+ - edit_rap_actual.UserGroups[0] == "Users@BUILTIN"
+ - edit_rap_actual.UserGroups[1] == "Guests@BUILTIN"
+ - edit_rap_actual.ComputerGroupType == "1"
+ - edit_rap_actual.ComputerGroup == "Administrators@BUILTIN"
+
+- name: test edit a RAP (indempotent)
+ win_rds_rap:
+ name: '{{ test_win_rds_rap_name }}'
+ description: 'Description of {{ test_win_rds_rap_name }}'
+ user_groups:
+ - users@builtin
+ - guests@builtin
+ computer_group_type: ad_network_resource_group
+ computer_group: Administrators@BUILTIN
+ allowed_ports:
+ - 3389
+ - 3390
+ - 3391
+ state: disabled
+ register: edit_rap_again
+
+- name: assert results of edit a RAP (indempotent)
+ assert:
+ that:
+ - edit_rap_again.changed == false
+
+- name: test allow all ports
+ win_rds_rap:
+ name: '{{ test_win_rds_rap_name }}'
+ allowed_ports: any
+ register: edit_rap_allow_all_ports
+
+- name: get result of allow all ports
+ ansible.windows.win_shell: Import-Module RemoteDesktopServices; Write-Host (Get-Item "RDS:\GatewayServer\RAP\{{ test_win_rds_rap_name }}\PortNumbers").CurrentValue
+ register: edit_rap_allow_all_ports_actual
+
+- name: assert results of allow all ports
+ assert:
+ that:
+ - edit_rap_allow_all_ports.changed == true
+ - edit_rap_allow_all_ports_actual.stdout_lines[0] == "*"
+
+- name: test remove RAP (check mode)
+ win_rds_rap:
+ name: '{{ test_win_rds_rap_name }}'
+ state: absent
+ register: remove_rap_check
+ check_mode: yes
+
+- name: get result of remove RAP (check mode)
+ ansible.windows.win_shell: Import-Module RemoteDesktopServices; Write-Host (Test-Path "RDS:\GatewayServer\RAP\{{ test_win_rds_rap_name }}")
+ register: remove_rap_actual_check
+
+- name: assert results of remove RAP (check mode)
+ assert:
+ that:
+ - remove_rap_check.changed == true
+ - remove_rap_actual_check.stdout_lines[0] == "True"
+
+- name: test remove RAP
+ win_rds_rap:
+ name: '{{ test_win_rds_rap_name }}'
+ state: absent
+ register: remove_rap
+
+- name: get result of remove RAP
+ ansible.windows.win_shell: Import-Module RemoteDesktopServices; Write-Host (Test-Path "RDS:\GatewayServer\RAP\{{ test_win_rds_rap_name }}")
+ register: remove_rap_actual
+
+- name: assert results of remove RAP
+ assert:
+ that:
+ - remove_rap.changed == true
+ - remove_rap_actual.stdout_lines[0] == "False"
+
+- name: test remove RAP (idempotent)
+ win_rds_rap:
+ name: '{{ test_win_rds_rap_name }}'
+ state: absent
+ register: remove_rap_again
+
+- name: get result of remove RAP (idempotent)
+ ansible.windows.win_shell: Import-Module RemoteDesktopServices; Write-Host (Test-Path "RDS:\GatewayServer\RAP\{{ test_win_rds_rap_name }}")
+ register: remove_rap_actual_again
+
+- name: assert results of remove RAP (idempotent)
+ assert:
+ that:
+ - remove_rap_again.changed == false
+ - remove_rap_actual_again.stdout_lines[0] == "False"
+
+- name: fail when create a new RAP without user group
+ win_rds_rap:
+ name: '{{ test_win_rds_rap_name }}'
+ state: present
+ register: new_rap_without_group
+ check_mode: yes
+ failed_when: "new_rap_without_group.msg != 'User groups must be defined to create a new RAP.'"
+
+- name: fail when create a new RAP with an empty user group list
+ win_rds_rap:
+ name: '{{ test_win_rds_rap_name }}'
+ user_groups: []
+ state: present
+ register: new_rap_empty_group_list
+ check_mode: yes
+ failed_when: "new_rap_empty_group_list.msg is not search('cannot be an empty list')"
+
+- name: fail when create a new RAP with an invalid user group
+ win_rds_rap:
+ name: '{{ test_win_rds_rap_name }}'
+ user_groups:
+ - fake_group
+ state: present
+ register: new_rap_invalid_group
+ check_mode: yes
+ failed_when: new_rap_invalid_group.changed != false or new_rap_invalid_group.msg is not search('is not a valid account')
+
+- name: fail when create a new RAP with an invalid AD computer group
+ win_rds_rap:
+ name: '{{ test_win_rds_rap_name }}'
+ user_groups:
+ - administrators
+ computer_group_type: ad_network_resource_group
+ computer_group: fake_ad_group
+ state: present
+ register: new_rap_invalid_ad_computer_group
+ check_mode: yes
+ failed_when: new_rap_invalid_ad_computer_group.changed != false or new_rap_invalid_ad_computer_group.msg is not search('is not a valid account')
+
+- name: fail when create a new RAP with an invalid gateway managed computer group
+ win_rds_rap:
+ name: '{{ test_win_rds_rap_name }}'
+ user_groups:
+ - administrators
+ computer_group_type: rdg_group
+ computer_group: fake_rdg_group
+ state: present
+ register: new_rap_invalid_rdg_computer_group
+ check_mode: yes
+ failed_when: new_rap_invalid_rdg_computer_group.changed != false or new_rap_invalid_rdg_computer_group.msg is not search('is not a valid gateway managed computer group')
+
+- name: fail when create a new RAP with invalid port numbers
+ win_rds_rap:
+ name: '{{ test_win_rds_rap_name }}'
+ user_groups:
+ - administrators
+ allowed_ports:
+ - '{{ item }}'
+ state: present
+ loop:
+ - invalid_port_number
+ - 65536
+ register: new_rap_invalid_port
+ check_mode: yes
+ failed_when: new_rap_invalid_port.changed != false or new_rap_invalid_port.msg is not search('is not a valid port number')
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_rds/tasks/win_rds_settings.yml b/ansible_collections/community/windows/tests/integration/targets/win_rds/tasks/win_rds_settings.yml
new file mode 100644
index 000000000..dff44963c
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_rds/tasks/win_rds_settings.yml
@@ -0,0 +1,66 @@
+- name: run tests with cleanup
+ block:
+ - name: gather facts
+ ansible.windows.setup:
+ filter: ansible_hostname
+
+ - name: ensure testing folders exists
+ ansible.windows.win_file:
+ path: '{{test_win_rds_settings_path}}'
+ state: directory
+
+ - name: deploy test artifacts
+ ansible.windows.win_template:
+ src: '{{item}}.j2'
+ dest: '{{test_win_rds_settings_path}}\{{item | basename}}'
+ with_items:
+ - rds_base_cfg.xml
+
+ - name: import RDS test configuration
+ ansible.windows.win_shell: |
+ $ts = Get-WmiObject Win32_TSGatewayServer -namespace root\cimv2\TerminalServices
+ $import_xml = Get-Content {{test_win_rds_settings_path}}\rds_base_cfg.xml
+ $import_result = $ts.Import(45, $import_xml)
+ exit $import_result.ReturnValue
+
+ - name: write certreq file
+ ansible.windows.win_copy:
+ content: |-
+ [NewRequest]
+ Subject = "CN={{ rds_cert_suject }}"
+ KeyLength = 2048
+ KeyAlgorithm = RSA
+ MachineKeySet = true
+ RequestType = Cert
+ KeyUsage = 0xA0 ; Digital Signature, Key Encipherment
+ [EnhancedKeyUsageExtension]
+ OID=1.3.6.1.5.5.7.3.1 ; Server Authentication
+ dest: '{{test_win_rds_settings_path}}\certreq.txt'
+
+ - name: create self signed cert from certreq
+ ansible.windows.win_command: certreq -new -machine {{test_win_rds_settings_path}}\certreq.txt {{test_win_rds_settings_path}}\certreqresp.txt
+
+ - name: register certificate thumbprint
+ raw: '(gci Cert:\LocalMachine\my | ? {$_.subject -eq "CN={{ rds_cert_suject }}"})[0].Thumbprint'
+ register: rds_cert_thumbprint
+
+ - name: run tests
+ include_tasks: win_rds_settings_tests.yml
+
+ always:
+ - name: restore RDS base configuration
+ ansible.windows.win_shell: |
+ $ts = Get-WmiObject Win32_TSGatewayServer -namespace root\cimv2\TerminalServices
+ $import_xml = Get-Content {{test_win_rds_settings_path}}\rds_base_cfg.xml
+ $import_result = $ts.Import(45, $import_xml)
+ exit $import_result.ReturnValue
+
+ - name: remove certificate
+ raw: 'remove-item cert:\localmachine\my\{{ item }} -force -ea silentlycontinue'
+ with_items:
+ - "{{ rds_cert_thumbprint.stdout_lines[0] }}"
+
+ - name: cleanup test artifacts
+ ansible.windows.win_file:
+ path: '{{test_win_rds_settings_path}}'
+ state: absent
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_rds/tasks/win_rds_settings_tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_rds/tasks/win_rds_settings_tests.yml
new file mode 100644
index 000000000..0b611eb95
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_rds/tasks/win_rds_settings_tests.yml
@@ -0,0 +1,89 @@
+---
+- name: test change RDS settings (check mode)
+ win_rds_settings:
+ max_connections: 50
+ certificate_hash: '{{rds_cert_thumbprint.stdout_lines[0]}}'
+ ssl_bridging: https_https
+ enable_only_messaging_capable_clients: yes
+ register: configure_rds_check
+ check_mode: yes
+
+- name: get result of change RDS settings (check mode)
+ ansible.windows.win_shell: |
+ Import-Module RemoteDesktopServices
+ (Get-Item RDS:\GatewayServer\MaxConnections).CurrentValue
+ (Get-Item RDS:\GatewayServer\SSLCertificate\Thumbprint).CurrentValue
+ (Get-Item RDS:\GatewayServer\SSLBridging).CurrentValue
+ (Get-Item RDS:\GatewayServer\EnableOnlyMessagingCapableClients).CurrentValue
+ register: configure_rds_actual_check
+
+- name: assert results of change RDS settings (check mode)
+ assert:
+ that:
+ - configure_rds_check.changed == true
+ - configure_rds_actual_check.stdout_lines[0] != "50"
+ - configure_rds_actual_check.stdout_lines[1] != rds_cert_thumbprint.stdout_lines[0]
+ - configure_rds_actual_check.stdout_lines[2] == "0"
+ - configure_rds_actual_check.stdout_lines[3] == "0"
+
+- name: test change RDS settings
+ win_rds_settings:
+ max_connections: 50
+ certificate_hash: '{{rds_cert_thumbprint.stdout_lines[0]}}'
+ ssl_bridging: https_https
+ enable_only_messaging_capable_clients: yes
+ register: configure_rds
+
+- name: get result of change RDS settings
+ ansible.windows.win_shell: |
+ Import-Module RemoteDesktopServices
+ (Get-Item RDS:\GatewayServer\MaxConnections).CurrentValue
+ (Get-Item RDS:\GatewayServer\SSLCertificate\Thumbprint).CurrentValue
+ (Get-Item RDS:\GatewayServer\SSLBridging).CurrentValue
+ (Get-Item RDS:\GatewayServer\EnableOnlyMessagingCapableClients).CurrentValue
+ register: configure_rds_actual
+
+- name: assert results of change RDS settings
+ assert:
+ that:
+ - configure_rds.changed == true
+ - configure_rds_actual.stdout_lines[0] == "50"
+ - configure_rds_actual.stdout_lines[1] == rds_cert_thumbprint.stdout_lines[0]
+ - configure_rds_actual.stdout_lines[2] == "2"
+ - configure_rds_actual.stdout_lines[3] == "1"
+
+- name: test change RDS settings (idempotent)
+ win_rds_settings:
+ max_connections: 50
+ certificate_hash: '{{rds_cert_thumbprint.stdout_lines[0]}}'
+ ssl_bridging: https_https
+ enable_only_messaging_capable_clients: yes
+ register: configure_rds_again
+
+- name: assert results of change RDS settings (idempotent)
+ assert:
+ that:
+ - configure_rds_again.changed == false
+
+- name: test disable connection limit
+ win_rds_settings:
+ max_connections: -1
+ register: disable_limit
+
+- name: get result of disable connection limit
+ ansible.windows.win_shell: |
+ Import-Module RemoteDesktopServices
+ (Get-Item RDS:\GatewayServer\MaxConnections).CurrentValue -eq (Get-Item RDS:\GatewayServer\MaxConnectionsAllowed).CurrentValue
+ register: disable_limit_actual
+
+- name: assert results of disable connection limit
+ assert:
+ that:
+ - disable_limit.changed == true
+ - disable_limit_actual.stdout_lines[0] == "True"
+
+- name: fail with invalid certificate thumbprint
+ win_rds_settings:
+ certificate_hash: 72E8BD0216FA14100192A3E8B7B150C65B4B0817
+ register: fail_invalid_cert
+ failed_when: fail_invalid_cert.msg is not search('Unable to locate certificate') \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_rds/templates/rds_base_cfg.xml.j2 b/ansible_collections/community/windows/tests/integration/targets/win_rds/templates/rds_base_cfg.xml.j2
new file mode 100644
index 000000000..5aa48ed84
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_rds/templates/rds_base_cfg.xml.j2
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-16"?>
+<?TSGateway version="1.0"?>
+<TsgServer>
+ <ServerName>{{ ansible_hostname }}</ServerName>
+ <ServerSettings>
+ <MaxConnections>4294967295</MaxConnections>
+ <UnlimitedConnections>1</UnlimitedConnections>
+ <CentralCapEnabled>0</CentralCapEnabled>
+ <RequestSOH>0</RequestSOH>
+ <OnlyConsentCapableClients>0</OnlyConsentCapableClients>
+ <LogEvents>
+ <LogEvent>
+ <Name>LogChannelDisconnect</Name>
+ <Enabled>1</Enabled>
+ </LogEvent>
+ <LogEvent>
+ <Name>LogFailureChannelConnect</Name>
+ <Enabled>1</Enabled>
+ </LogEvent>
+ <LogEvent>
+ <Name>LogFailureConnectionAuthorizationCheck</Name>
+ <Enabled>1</Enabled>
+ </LogEvent>
+ <LogEvent>
+ <Name>LogFailureResourceAuthorizationCheck</Name>
+ <Enabled>1</Enabled>
+ </LogEvent>
+ <LogEvent>
+ <Name>LogSuccessfulChannelConnect</Name>
+ <Enabled>1</Enabled>
+ </LogEvent>
+ <LogEvent>
+ <Name>LogSuccessfulConnectionAuthorizationCheck</Name>
+ <Enabled>1</Enabled>
+ </LogEvent>
+ <LogEvent>
+ <Name>LogSuccessfulResourceAuthorizationCheck</Name>
+ <Enabled>1</Enabled>
+ </LogEvent>
+ </LogEvents>
+ <AuthenticationPlugin>native</AuthenticationPlugin>
+ <AuthorizationPlugin>native</AuthorizationPlugin>
+ <ConsentMessageText/>
+ <AdminMessageText/>
+ <AdminMsgStartDate/>
+ <AdminMsgEndDate/>
+ <SslBridging>0</SslBridging>
+ <HttpIPAddress>*</HttpIPAddress>
+ <UdpIPAddress>*</UdpIPAddress>
+ <HttpPort>443</HttpPort>
+ <UdpPort>3391</UdpPort>
+ <IsUdpEnabled>1</IsUdpEnabled>
+ <EnforceChannelBinding>1</EnforceChannelBinding>
+ </ServerSettings>
+ <Caps/>
+ <Raps/>
+ <ResourceGroups/>
+</TsgServer> \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_region/aliases b/ansible_collections/community/windows/tests/integration/targets/win_region/aliases
new file mode 100644
index 000000000..3cf5b97e8
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_region/aliases
@@ -0,0 +1 @@
+shippable/windows/group3
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_region/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_region/tasks/main.yml
new file mode 100644
index 000000000..be2b8be21
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_region/tasks/main.yml
@@ -0,0 +1,252 @@
+# test code for the win_region module
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+- name: expect failure when only setting copy_settings
+ win_region:
+ copy_settings: False
+ register: actual
+ failed_when: actual.msg != "An argument for 'format', 'location' or 'unicode_language' needs to be supplied"
+
+- name: expect failure when using invalid geo id for the location
+ win_region:
+ location: 111111
+ register: actual
+ failed_when: actual.msg != "The argument location '111111' does not contain a valid Geo ID"
+
+- name: expect failure when using invalid culture for format
+ win_region:
+ format: ab-CD
+ register: actual
+ failed_when: actual.msg != "The argument format 'ab-CD' does not contain a valid Culture Name"
+
+- name: expect failure when using invalid culture for unicode_language
+ win_region:
+ unicode_language: ab-CD
+ register: actual
+ failed_when: actual.msg != "The argument unicode_language 'ab-CD' does not contain a valid Culture Name"
+
+- name: set settings all to English Australia before tests for a baseline
+ win_region:
+ location: 12
+ format: en-AU
+ unicode_language: en-AU
+
+- name: reboot server to set properties
+ ansible.windows.win_reboot:
+
+- name: check that changing location in check mode works
+ win_region:
+ location: 244
+ register: check_location
+ check_mode: yes
+
+- name: get current location value
+ ansible.windows.win_command: powershell (Get-ItemProperty -Path 'HKCU:\Control Panel\International\Geo').Nation
+ register: actual_location
+
+- name: check assertion about location change in check mode
+ assert:
+ that:
+ - "actual_location.stdout_lines[0] == '12'" # Corresponds to en-AU
+ - "check_location is changed"
+ - "check_location.restart_required == False"
+
+- name: set location to United States
+ win_region:
+ location: 244
+ register: location
+
+- name: get current location value
+ ansible.windows.win_command: powershell (Get-ItemProperty -Path 'HKCU:\Control Panel\International\Geo').Nation
+ register: actual_location
+
+- name: check assertion about location change
+ assert:
+ that:
+ - "actual_location.stdout_lines[0] == '244'" # Corresponds to en-US
+ - "location is changed"
+ - "location.restart_required == False"
+
+- name: set location to United States again
+ win_region:
+ location: 244
+ register: location_again
+
+- name: check that the result did not change
+ assert:
+ that:
+ - "location_again is not changed"
+ - "location_again.restart_required == False"
+
+- name: set format to English United States in check mode
+ win_region:
+ format: en-US
+ register: check_format
+ check_mode: yes
+
+- name: get actual format value from check mode
+ ansible.windows.win_command: powershell (Get-Culture).Name
+ register: actual_format
+
+- name: check assertion about location change in check mode
+ assert:
+ that:
+ - "actual_format.stdout_lines[0] == 'en-AU'"
+ - "check_format is changed"
+ - "check_format.restart_required == False"
+
+- name: set format to English United States
+ win_region:
+ format: en-US
+ register: format
+
+- name: get actual format value
+ ansible.windows.win_command: powershell (Get-Culture).Name
+ register: actual_format
+
+- name: check assertion about format change
+ assert:
+ that:
+ - "actual_format.stdout_lines[0] == 'en-US'"
+ - "format is changed"
+ - "format.restart_required == False"
+
+- name: set format to English United States again
+ win_region:
+ format: en-US
+ register: format_again
+
+- name: check that the result did not change
+ assert:
+ that:
+ - "format_again is not changed"
+ - "format_again.restart_required == False"
+
+- name: set unicode_language to English United States in check mode
+ win_region:
+ unicode_language: en-US
+ register: check_unicode
+ check_mode: yes
+
+- name: get actual unicode values
+ ansible.windows.win_command: powershell (Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Nls\Language').Default
+ register: actual_unicode
+
+- name: check assertion about unicode language change in check mode
+ assert:
+ that:
+ - "actual_unicode.stdout_lines[0] == '0c09'"
+ - "check_unicode is changed"
+ - "check_unicode.restart_required == True"
+
+- name: set unicode_language to English United States
+ win_region:
+ unicode_language: en-US
+ register: unicode
+
+- name: reboot the server after changing unicode language
+ ansible.windows.win_reboot:
+ when: unicode.restart_required
+
+- name: get actual unicode value
+ ansible.windows.win_command: powershell (Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Nls\Language').Default
+ register: actual_unicode
+
+- name: check assertion about unicode language change
+ assert:
+ that:
+ - "actual_unicode.stdout_lines[0] == '0409'" # corresponds to en-US
+ - "unicode is changed"
+ - "unicode.restart_required == True"
+
+- name: set unicode_language to English United States again
+ win_region:
+ unicode_language: en-US
+ register: unicode_again
+
+- name: check that the result did not change
+ assert:
+ that:
+ - "unicode_again is not changed"
+ - "unicode_again.restart_required == False"
+
+- name: copy settings when setting to the same format check mode
+ win_region:
+ format: en-US
+ copy_settings: True
+ register: check_copy_same
+ check_mode: yes
+
+- name: check that the result did not change in check mode
+ assert:
+ that:
+ - "check_copy_same is not changed"
+ - "check_copy_same.restart_required == False"
+
+- name: copy settings when setting to the same format
+ win_region:
+ format: en-US
+ copy_settings: True
+ register: copy_same
+
+- name: check that the result did not change
+ assert:
+ that:
+ - "copy_same is not changed"
+ - "copy_same.restart_required == False"
+
+- name: copy setting when setting to a different format
+ win_region:
+ format: en-GB
+ copy_settings: True
+ register: copy
+
+- name: get actual format value after copy_settings
+ ansible.windows.win_command: powershell (Get-Culture).Name
+ register: actual_copy
+
+- name: get locale name for local service registry hive
+ ansible.windows.win_command: powershell "New-PSDrive -Name HKU -PSProvider Registry -Root Registry::HKEY_USERS | Out-Null; (Get-ItemProperty 'HKU:\S-1-5-19\Control Panel\International').LocaleName"
+ register: actual_local
+
+- name: get locale name for network service registry hive
+ ansible.windows.win_command: powershell "New-PSDrive -Name HKU -PSProvider Registry -Root Registry::HKEY_USERS | Out-Null; (Get-ItemProperty 'HKU:\S-1-5-20\Control Panel\International').LocaleName"
+ register: actual_network
+
+- name: load temp hive
+ ansible.windows.win_command: reg load HKU\TEMP C:\Users\Default\NTUSER.DAT
+
+- name: get locale name for default registry hive
+ ansible.windows.win_command: powershell "New-PSDrive -Name HKU -PSProvider Registry -Root Registry::HKEY_USERS | Out-Null; (Get-ItemProperty 'HKU:\TEMP\Control Panel\International').LocaleName"
+ register: actual_temp
+
+- name: unload temp hive
+ ansible.windows.win_command: reg unload HKU\TEMP
+
+- name: get locale name for default registry hive
+ ansible.windows.win_command: powershell "New-PSDrive -Name HKU -PSProvider Registry -Root Registry::HKEY_USERS | Out-Null; (Get-ItemProperty 'HKU:\.DEFAULT\Control Panel\International').LocaleName"
+ register: actual_default
+
+- name: check assertions about copy setting when setting to a different format
+ assert:
+ that:
+ - "actual_copy.stdout_lines[0] == 'en-GB'"
+ - "actual_local.stdout_lines[0] == 'en-GB'"
+ - "actual_network.stdout_lines[0] == 'en-GB'"
+ - "actual_temp.stdout_lines[0] == 'en-GB'"
+ - "actual_default.stdout_lines[0] == 'en-GB'"
+ - "copy is changed"
+ - "copy.restart_required == False"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_regmerge/aliases b/ansible_collections/community/windows/tests/integration/targets/win_regmerge/aliases
new file mode 100644
index 000000000..423ce3910
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_regmerge/aliases
@@ -0,0 +1 @@
+shippable/windows/group2
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_regmerge/files/settings1.reg b/ansible_collections/community/windows/tests/integration/targets/win_regmerge/files/settings1.reg
new file mode 100644
index 000000000..baec75b2a
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_regmerge/files/settings1.reg
Binary files differ
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_regmerge/files/settings2.reg b/ansible_collections/community/windows/tests/integration/targets/win_regmerge/files/settings2.reg
new file mode 100644
index 000000000..fc2612cb8
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_regmerge/files/settings2.reg
Binary files differ
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_regmerge/files/settings3.reg b/ansible_collections/community/windows/tests/integration/targets/win_regmerge/files/settings3.reg
new file mode 100644
index 000000000..fbe7411c9
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_regmerge/files/settings3.reg
Binary files differ
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_regmerge/meta/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_regmerge/meta/main.yml
new file mode 100644
index 000000000..9f37e96cd
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_regmerge/meta/main.yml
@@ -0,0 +1,2 @@
+dependencies:
+- setup_remote_tmp_dir
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_regmerge/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_regmerge/tasks/main.yml
new file mode 100644
index 000000000..af640eb93
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_regmerge/tasks/main.yml
@@ -0,0 +1,133 @@
+# test code for the win_regmerge module
+# (c) 2014, Michael DeHaan <michael.dehaan@gmail.com>
+
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+# clear the area of the registry we are using for tests
+- name: remove setting
+ ansible.windows.win_regedit:
+ key: 'HKLM:\SOFTWARE\Wow6432Node\Cow Corp'
+ state: absent
+
+# copy over some registry files to work with
+- name: copy over some registry files to work with
+ ansible.windows.win_copy: src={{item}} dest={{ remote_tmp_dir }}\\{{item}}
+ with_items:
+ - settings1.reg
+ - settings2.reg
+ - settings3.reg
+
+# test 1 - basic test of changed behaviour
+# merge in REG_SZ
+- name: test 1 merge in a setting
+ win_regmerge:
+ path: "{{ remote_tmp_dir }}\\settings1.reg"
+ register: merge11_result
+
+- assert:
+ that:
+ - "merge11_result.changed == true"
+
+# re run the merge
+- name: test 1 merge in the setting again
+ win_regmerge:
+ path: "{{ remote_tmp_dir }}\\settings1.reg"
+ register: merge12_result
+
+# without a compare to key, should always report changed
+- assert:
+ that:
+ - "merge12_result.changed == true"
+# assert changed false
+
+# prune reg key
+- name: test 1 remove setting
+ ansible.windows.win_regedit:
+ key: 'HKLM:\SOFTWARE\Wow6432Node\Cow Corp'
+ state: absent
+
+#
+# test 2, observe behaviour when compare_to param is set
+#
+- name: test 2 merge in a setting
+ win_regmerge:
+ path: "{{ remote_tmp_dir }}\\settings1.reg"
+ compare_to: 'HKLM:\SOFTWARE\Wow6432Node\Cow Corp\Moosic\ILikeToMooveIt'
+ register: merge21_result
+
+- assert:
+ that:
+ - "merge21_result.changed == true"
+
+# re run the merge
+- name: test 2 merge in the setting again but with compare_key
+ win_regmerge:
+ path: "{{ remote_tmp_dir }}\\settings1.reg"
+ compare_to: 'HKLM:\SOFTWARE\Wow6432Node\Cow Corp\Moosic\ILikeToMooveIt'
+ register: merge22_result
+
+# with a compare to key, should now report not changed
+- assert:
+ that:
+ - "merge22_result.changed == false"
+# assert changed false
+
+# prune the contents of the registry from the parent of the compare key downwards
+- name: test 2 clean up remove setting
+ ansible.windows.win_regedit:
+ key: 'HKLM:\SOFTWARE\Wow6432Node\Cow Corp'
+ state: absent
+
+# test 3 merge in more complex settings
+- name: test 3 merge in a setting
+ win_regmerge:
+ path: "{{ remote_tmp_dir }}\\settings3.reg"
+ compare_to: 'HKLM:\SOFTWARE\Wow6432Node\Cow Corp\Moo Monitor'
+ register: merge31_result
+
+- assert:
+ that:
+ - "merge31_result.changed == true"
+
+# re run the merge
+- name: test 3 merge in the setting again but with compare_key check
+ win_regmerge:
+ path: "{{ remote_tmp_dir }}\\settings3.reg"
+ compare_to: 'HKLM:\SOFTWARE\Wow6432Node\Cow Corp\Moo Monitor'
+ register: merge32_result
+
+# with a compare to key, should now report not changed
+- assert:
+ that:
+ - "merge32_result.changed == false"
+# assert changed false
+
+# prune the contents of the registry from the compare key downwards
+- name: test 3 clean up remove setting
+ ansible.windows.win_regedit:
+ key: 'HKLM:\SOFTWARE\Wow6432Node\Cow Corp'
+ state: absent
+
+# clean up registry files
+
+- name: clean up registry files
+ ansible.windows.win_file: path={{ remote_tmp_dir }}\\{{item}} state=absent
+ with_items:
+ - settings1.reg
+ - settings2.reg
+ - settings3.reg
+
+# END OF win_regmerge tests
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_regmerge/templates/win_line_ending.j2 b/ansible_collections/community/windows/tests/integration/targets/win_regmerge/templates/win_line_ending.j2
new file mode 100644
index 000000000..d0cefd76f
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_regmerge/templates/win_line_ending.j2
@@ -0,0 +1,4 @@
+#jinja2: newline_sequence:'\r\n'
+{{ templated_var }}
+{{ templated_var }}
+{{ templated_var }}
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_regmerge/vars/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_regmerge/vars/main.yml
new file mode 100644
index 000000000..1e8f64ccf
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_regmerge/vars/main.yml
@@ -0,0 +1 @@
+templated_var: templated_var_loaded
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_route/aliases b/ansible_collections/community/windows/tests/integration/targets/win_route/aliases
new file mode 100644
index 000000000..4f4664b68
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_route/aliases
@@ -0,0 +1 @@
+shippable/windows/group5
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_route/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_route/defaults/main.yml
new file mode 100644
index 000000000..a77ebc16c
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_route/defaults/main.yml
@@ -0,0 +1,3 @@
+---
+default_gateway: 192.168.1.1
+destination_ip_address: 192.168.2.10
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_route/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_route/tasks/main.yml
new file mode 100644
index 000000000..4bbdee5b5
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_route/tasks/main.yml
@@ -0,0 +1,29 @@
+---
+# test code for the win_psmodule module when using winrm connection
+# (c) 2017, Daniele Lazzari <lazzari@mailup.com>
+
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+
+- name: get os info
+ ansible.windows.win_shell: '[Environment]::OSVersion.Version -ge [Version]"6.3"'
+ register: os
+
+- name: Perform with os Windows 2012R2 or newer
+ when: os.stdout_lines[0] == "True"
+ block:
+ - name: run all tasks
+ include: tests.yml
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_route/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_route/tasks/tests.yml
new file mode 100644
index 000000000..dc456068a
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_route/tasks/tests.yml
@@ -0,0 +1,79 @@
+---
+- name: add a static route
+ win_route:
+ destination: "{{ destination_ip_address }}/32"
+ gateway: "{{ default_gateway }}"
+ metric: 1
+ state: present
+ register: route
+
+- name: check if route successfully added
+ ansible.windows.win_shell: (Get-CimInstance win32_ip4PersistedrouteTable -Filter "Destination = '{{ destination_ip_address }}'").Caption
+ register: route_added
+
+- name: check route default gateway
+ ansible.windows.win_shell: (Get-CimInstance win32_ip4PersistedrouteTable -Filter "Destination = '{{ destination_ip_address }}'").NextHop
+ register: route_gateway
+
+- name: test if route successfully added
+ assert:
+ that:
+ - route is changed
+ - route_added.stdout_lines[0] == "{{ destination_ip_address }}"
+ - route_gateway.stdout_lines[0] == "{{ default_gateway }}"
+
+- name: add a static route to test idempotency
+ win_route:
+ destination: "{{ destination_ip_address }}/32"
+ gateway: "{{ default_gateway }}"
+ metric: 1
+ state: present
+ register: idempotent_route
+
+- name: test idempotency
+ assert:
+ that:
+ - idempotent_route is not changed
+ - idempotent_route.output == "Static route already exists"
+
+- name: remove route
+ win_route:
+ destination: "{{ destination_ip_address }}/32"
+ state: absent
+ register: route_removed
+
+- name: check route is removed
+ ansible.windows.win_shell: Get-CimInstance win32_ip4PersistedrouteTable -Filter "Destination = '{{ destination_ip_address }}'"
+ register: check_route_removed
+
+- name: test route is removed
+ assert:
+ that:
+ - route_removed is changed
+ - check_route_removed.stdout == ''
+
+- name: remove static route to test idempotency
+ win_route:
+ destination: "{{ destination_ip_address }}/32"
+ state: absent
+ register: idempotent_route_removed
+
+- name: test idempotency
+ assert:
+ that:
+ - idempotent_route_removed is not changed
+ - idempotent_route_removed.output == "No route to remove"
+
+- name: add route to wrong ip address
+ win_route:
+ destination: "715.18.0.0/32"
+ gateway: "{{ default_gateway }}"
+ metric: 1
+ state: present
+ ignore_errors: yes
+ register: wrong_ip
+
+- name: test route to wrong ip address
+ assert:
+ that:
+ - wrong_ip is failed
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_say/aliases b/ansible_collections/community/windows/tests/integration/targets/win_say/aliases
new file mode 100644
index 000000000..4cd27b3cb
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_say/aliases
@@ -0,0 +1 @@
+shippable/windows/group1
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_say/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_say/tasks/main.yml
new file mode 100644
index 000000000..5b37a19ba
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_say/tasks/main.yml
@@ -0,0 +1,44 @@
+# CI hosts don't have a valid Speech package so we rely on check mode for basic
+# sanity tests
+---
+- name: Warn of impending deployment
+ win_say:
+ msg: Warning, deployment commencing in 5 minutes, please log out.
+ check_mode: "{{ win_say_check_mode |default('yes') }}"
+
+- name: Using a specified voice and a start sound
+ win_say:
+ msg: Warning, deployment commencing in 5 minutes, please log out.
+ start_sound_path: C:\Windows\Media\ding.wav
+ voice: Microsoft Hazel Desktop
+ check_mode: "{{ win_say_check_mode |default('yes') }}"
+
+- name: Example with start and end sound
+ win_say:
+ msg: New software installed
+ start_sound_path: C:\Windows\Media\Windows Balloon.wav
+ end_sound_path: C:\Windows\Media\chimes.wav
+ check_mode: "{{ win_say_check_mode |default('yes') }}"
+
+- name: Create message file
+ ansible.windows.win_copy:
+ content: Stay calm and carry on
+ dest: C:\Windows\Temp\win_say_message.txt
+
+- name: Text from file example
+ win_say:
+ msg_file: C:\Windows\Temp\win_say_message.txt
+ start_sound_path: C:\Windows\Media\Windows Balloon.wav
+ end_sound_path: C:\Windows\Media\chimes.wav
+ check_mode: "{{ win_say_check_mode |default('yes') }}"
+
+- name: Remove message file
+ ansible.windows.win_file:
+ path: C:\Windows\Temp\win_say_message.txt
+ state: absent
+
+- name: Different speech speed
+ win_say:
+ speech_speed: 5
+ msg: Stay calm and proceed to the closest fire exit.
+ check_mode: "{{ win_say_check_mode |default('yes') }}"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/aliases b/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/aliases
new file mode 100644
index 000000000..4f4664b68
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/aliases
@@ -0,0 +1 @@
+shippable/windows/group5
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/defaults/main.yml
new file mode 100644
index 000000000..f6cd77da3
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/defaults/main.yml
@@ -0,0 +1,15 @@
+---
+test_scheduled_task_name: Ansible Test
+test_scheduled_task_path: \Ansible Test Folder
+test_scheduled_task_user: MooCow
+test_scheduled_task_pass: Password01
+
+test_scheduled_task_invalid_chars:
+ - '\'
+ - '/'
+ - ':'
+ - '*'
+ - '"'
+ - '<'
+ - '>'
+ - '|'
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/tasks/clean.yml b/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/tasks/clean.yml
new file mode 100644
index 000000000..df7bbd06e
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/tasks/clean.yml
@@ -0,0 +1,16 @@
+# cleans up each test to ensure a blank slate
+---
+- win_scheduled_task:
+ name: '{{item.name}}'
+ path: '{{item.path|default(omit)}}'
+ state: absent
+ with_items:
+ - name: Task # old tests
+ path: \Path
+ - name: '{{test_scheduled_task_name}}'
+ - name: '{{test_scheduled_task_name}}'
+ path: '{{test_scheduled_task_path}}'
+
+- ansible.windows.win_user:
+ name: '{{test_scheduled_task_user}}'
+ state: absent
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/tasks/failures.yml b/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/tasks/failures.yml
new file mode 100644
index 000000000..57c4e4895
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/tasks/failures.yml
@@ -0,0 +1,161 @@
+# test out the known failure cases to ensure we have decent error messages
+---
+# ensure we have good error messages for invalid task chars
+- name: fail to create tasks with invalid characters
+ win_scheduled_task:
+ name: "Bad {{ item }} {{ test_scheduled_task_name }}"
+ state: present
+ actions:
+ - path: cmd.exe
+ arguments: /c echo hi
+ loop: "{{ test_scheduled_task_invalid_chars }}"
+ register: fail_invalid_chars
+ failed_when: fail_invalid_chars is not failed or fail_invalid_chars.msg is not search('The following characters are not valid')
+
+- name: fail create task without an action
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ register: fail_create_without_action
+ failed_when: fail_create_without_action.msg != 'cannot create a task with no actions, set at least one action with a path to an executable'
+
+- name: fail both username and group are set
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ username: '{{ansible_user}}'
+ group: '{{ansible_user}}'
+ register: fail_username_and_group
+ failed_when: fail_username_and_group.msg != 'username and group can not be set at the same time'
+
+- name: fail logon type s4u but no password set
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ logon_type: s4u
+ register: fail_lt_s4u_not_set
+ failed_when: fail_lt_s4u_not_set.msg != 'password must be set when logon_type=s4u'
+
+- name: fail logon type group but no group set
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ logon_type: group
+ register: fail_lt_group_not_set
+ failed_when: fail_lt_group_not_set.msg != 'group must be set when logon_type=group'
+
+- name: fail logon type service but non service user set
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ logon_type: service_account
+ username: '{{ansible_user}}'
+ register: fail_lt_service_invalid_user
+ failed_when: fail_lt_service_invalid_user.msg != 'username must be SYSTEM, LOCAL SERVICE or NETWORK SERVICE when logon_type=service_account'
+
+- name: fail trigger with no type
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ triggers:
+ - delay: test
+ register: fail_trigger_no_type
+ failed_when: fail_trigger_no_type.msg != "a trigger entry must contain a key 'type' with a value of 'event', 'time', 'daily', 'weekly', 'monthly', 'monthlydow', 'idle', 'registration', 'boot', 'logon', 'session_state_change'"
+
+- name: fail trigger with datetime in incorrect format
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ triggers:
+ - type: time
+ start_boundary: fake
+ register: fail_trigger_invalid_datetime
+ failed_when: fail_trigger_invalid_datetime.msg != "trigger option 'start_boundary' must be in the format 'YYYY-MM-DDThh:mm:ss' format but was 'fake'"
+
+- name: fail trigger with duration in incorrect format
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ triggers:
+ - type: boot
+ execution_time_limit: fake
+ register: fail_trigger_invalid_duration
+ failed_when: fail_trigger_invalid_duration.msg != "trigger option 'execution_time_limit' must be in the XML duration format but was 'fake'"
+
+- name: fail trigger option invalid day of the week
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ triggers:
+ - type: weekly
+ start_boundary: '2000-01-01T00:00:01'
+ days_of_week: fakeday
+ register: fail_trigger_invalid_day_of_week
+ failed_when: fail_trigger_invalid_day_of_week.msg != "invalid day of week 'fakeday', check the spelling matches the full day name"
+
+- name: fail trigger option invalid day of the month
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ triggers:
+ - type: monthly
+ start_boundary: '2000-01-01T00:00:01'
+ days_of_month: 35
+ register: fail_trigger_invalid_day_of_month
+ failed_when: fail_trigger_invalid_day_of_month.msg != "invalid day of month '35', please specify numbers from 1-31"
+
+- name: fail trigger option invalid week of the month
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ triggers:
+ - type: monthlydow
+ start_boundary: '2000-01-01T00:00:01'
+ weeks_of_month: 5
+ register: fail_trigger_invalid_week_of_month
+ failed_when: fail_trigger_invalid_week_of_month.msg != "invalid week of month '5', please specify weeks from 1-4"
+
+- name: fail trigger option invalid month of the year
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ triggers:
+ - type: monthlydow
+ start_boundary: '2000-01-01T00:00:01'
+ months_of_year: fakemonth
+ register: fail_trigger_invalid_month_of_year
+ failed_when: fail_trigger_invalid_month_of_year.msg != "invalid month name 'fakemonth', please specify full month name"
+
+- name: fail trigger repetition with duration in incorrect format
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ triggers:
+ - type: boot
+ repetition:
+ - duration: fake
+ register: fail_trigger_repetition_invalid_duration
+ failed_when: fail_trigger_repetition_invalid_duration.msg != "trigger option 'duration' must be in the XML duration format but was 'fake'"
+
+- name: fail trigger repetition with interval in incorrect format
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ triggers:
+ - type: boot
+ repetition:
+ - interval: fake
+ register: fail_trigger_repetition_invalid_interval
+ failed_when: fail_trigger_repetition_invalid_interval.msg != "trigger option 'interval' must be in the XML duration format but was 'fake'"
+
+- name: fail trigger repetition option interval greater than duration
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ triggers:
+ - type: boot
+ repetition:
+ - interval: PT5M
+ duration: PT1M
+ register: fail_trigger_repetition_interval_greater_than_duration
+ failed_when: fail_trigger_repetition_interval_greater_than_duration.msg != "trigger repetition option 'interval' value 'PT5M' must be less than or equal to 'duration' value 'PT1M'"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/tasks/main.yml
new file mode 100644
index 000000000..5142ac9ab
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/tasks/main.yml
@@ -0,0 +1,24 @@
+---
+- name: remove test tasks before test
+ include_tasks: clean.yml
+
+- block:
+ - name: Test failure scenarios
+ include_tasks: failures.yml
+
+ - name: Test normal scenarios
+ include_tasks: tests.yml
+
+ - include_tasks: clean.yml
+
+ - name: Test principals
+ include_tasks: principals.yml
+
+ - include_tasks: clean.yml
+
+ - name: Test triggers
+ include_tasks: triggers.yml
+
+ always:
+ - name: remove test tasks after test
+ include_tasks: clean.yml
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/tasks/principals.yml b/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/tasks/principals.yml
new file mode 100644
index 000000000..9961855f8
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/tasks/principals.yml
@@ -0,0 +1,436 @@
+---
+- name: create test user
+ ansible.windows.win_user:
+ name: '{{test_scheduled_task_user}}'
+ password: '{{test_scheduled_task_pass}}'
+ state: present
+ groups:
+ - Administrators
+
+- name: task with password principal (check mode)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ username: '{{test_scheduled_task_user}}'
+ password: '{{test_scheduled_task_pass}}'
+ logon_type: password
+ update_password: no
+ actions:
+ - path: cmd.exe
+ register: task_with_password_check
+ check_mode: yes
+
+- name: get result of task with password principal (check mode)
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: task_with_password_result_check
+
+- name: assert results of task with password principal (check mode)
+ assert:
+ that:
+ - task_with_password_check is changed
+ - task_with_password_result_check.task_exists == False
+
+- name: task with password principal
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ username: '{{test_scheduled_task_user}}'
+ password: '{{test_scheduled_task_pass}}'
+ logon_type: password
+ update_password: no
+ actions:
+ - path: cmd.exe
+ register: task_with_password
+
+- name: get result of task with password principal
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: task_with_password_result
+
+- name: assert results of task with password principal
+ assert:
+ that:
+ - task_with_password is changed
+ - task_with_password_result.task_exists == True
+ - task_with_password_result.principal.group_id == None
+ - task_with_password_result.principal.logon_type == "TASK_LOGON_PASSWORD"
+ - task_with_password_result.principal.run_level == "TASK_RUNLEVEL_LUA"
+ - task_with_password_result.principal.user_id.endswith(test_scheduled_task_user)
+
+- name: task with password principal (idempotent)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ username: '{{test_scheduled_task_user}}'
+ password: '{{test_scheduled_task_pass}}'
+ logon_type: password
+ update_password: no
+ actions:
+ - path: cmd.exe
+ register: task_with_password_again
+
+- name: assert results of task with password principal (idempotent)
+ assert:
+ that:
+ - task_with_password_again is not changed
+
+- name: task with password principal force pass change
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ username: '{{test_scheduled_task_user}}'
+ password: '{{test_scheduled_task_pass}}'
+ logon_type: password
+ update_password: yes
+ actions:
+ - path: cmd.exe
+ register: task_with_password_force_update
+
+- name: assert results of task with password principal force pass change
+ assert:
+ that:
+ - task_with_password_force_update is changed
+
+- name: task with s4u principal (check mode)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ username: '{{test_scheduled_task_user}}'
+ password: '{{test_scheduled_task_pass}}'
+ logon_type: s4u
+ update_password: no
+ actions:
+ - path: cmd.exe
+ register: task_with_s4u_check
+ check_mode: yes
+
+- name: get result of task with s4u principal (check mode)
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: task_with_s4u_result_check
+
+- name: assert results of task with s4u principal (check mode)
+ assert:
+ that:
+ - task_with_s4u_check is changed
+ - task_with_s4u_result_check.task_exists == True
+ - task_with_s4u_result_check.principal.group_id == None
+ - task_with_s4u_result_check.principal.logon_type == "TASK_LOGON_PASSWORD"
+ - task_with_s4u_result_check.principal.run_level == "TASK_RUNLEVEL_LUA"
+ - task_with_s4u_result_check.principal.user_id.endswith(test_scheduled_task_user)
+
+- name: task with s4u principal
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ username: '{{test_scheduled_task_user}}'
+ password: '{{test_scheduled_task_pass}}'
+ logon_type: s4u
+ update_password: no
+ actions:
+ - path: cmd.exe
+ register: task_with_s4u
+
+- name: get result of task with s4u principal
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: task_with_s4u_result
+
+- name: assert results of task with s4u principal
+ assert:
+ that:
+ - task_with_s4u is changed
+ - task_with_s4u_result.task_exists == True
+ - task_with_s4u_result.principal.group_id == None
+ - task_with_s4u_result.principal.logon_type == "TASK_LOGON_S4U"
+ - task_with_s4u_result.principal.run_level == "TASK_RUNLEVEL_LUA"
+ - task_with_s4u_result.principal.user_id.endswith(test_scheduled_task_user)
+
+- name: task with s4u principal (idempotent)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ username: '{{test_scheduled_task_user}}'
+ password: '{{test_scheduled_task_pass}}'
+ logon_type: s4u
+ update_password: no
+ actions:
+ - path: cmd.exe
+ register: task_with_s4u_again
+
+- name: assert results of task with s4u principal (idempotent)
+ assert:
+ that:
+ - task_with_s4u_again is not changed
+
+- name: task with interactive principal (check mode)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ username: '{{test_scheduled_task_user}}'
+ logon_type: interactive_token
+ actions:
+ - path: cmd.exe
+ register: task_with_interactive_check
+ check_mode: yes
+
+- name: get result of task with interactive principal (check mode)
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: task_with_interactive_result_check
+
+- name: assert results of task with interactive principal (check mode)
+ assert:
+ that:
+ - task_with_interactive_check is changed
+ - task_with_interactive_result_check.task_exists == True
+ - task_with_interactive_result_check.principal.group_id == None
+ - task_with_interactive_result_check.principal.logon_type == "TASK_LOGON_S4U"
+ - task_with_interactive_result_check.principal.run_level == "TASK_RUNLEVEL_LUA"
+ - task_with_interactive_result_check.principal.user_id.endswith(test_scheduled_task_user)
+
+- name: task with interactive principal
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ username: '{{test_scheduled_task_user}}'
+ logon_type: interactive_token
+ actions:
+ - path: cmd.exe
+ register: task_with_interactive
+
+- name: get result of task with interactive principal
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: task_with_interactive_result
+
+- name: assert results of task with interactive principal
+ assert:
+ that:
+ - task_with_interactive is changed
+ - task_with_interactive_result.task_exists == True
+ - task_with_interactive_result.principal.group_id == None
+ - task_with_interactive_result.principal.logon_type == "TASK_LOGON_INTERACTIVE_TOKEN"
+ - task_with_interactive_result.principal.run_level == "TASK_RUNLEVEL_LUA"
+ - task_with_interactive_result.principal.user_id.endswith(test_scheduled_task_user)
+
+- name: task with interactive principal (idempotent)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ username: '{{test_scheduled_task_user}}'
+ logon_type: interactive_token
+ actions:
+ - path: cmd.exe
+ register: task_with_interactive_again
+
+- name: assert results of task with interactive principal (idempotent)
+ assert:
+ that:
+ - task_with_interactive_again is not changed
+
+- name: task with group principal (check mode)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ group: Administrators
+ logon_type: group
+ actions:
+ - path: cmd.exe
+ register: task_with_group_check
+ check_mode: yes
+
+- name: get result of task with group principal (check mode)
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: task_with_group_result_check
+
+- name: assert results of task with group principal (check mode)
+ assert:
+ that:
+ - task_with_group_check is changed
+ - task_with_group_result_check.task_exists == True
+ - task_with_group_result_check.principal.group_id == None
+ - task_with_group_result_check.principal.logon_type == "TASK_LOGON_INTERACTIVE_TOKEN"
+ - task_with_group_result_check.principal.run_level == "TASK_RUNLEVEL_LUA"
+ - task_with_group_result_check.principal.user_id.endswith(test_scheduled_task_user)
+
+- name: task with group principal
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ group: Administrators
+ logon_type: group
+ actions:
+ - path: cmd.exe
+ register: task_with_group
+
+- name: get result of task with group principal
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: task_with_group_result
+
+- name: assert results of task with group principal
+ assert:
+ that:
+ - task_with_group is changed
+ - task_with_group_result.task_exists == True
+ - task_with_group_result.principal.group_id == "BUILTIN\\Administrators"
+ - task_with_group_result.principal.logon_type == "TASK_LOGON_GROUP"
+ - task_with_group_result.principal.run_level == "TASK_RUNLEVEL_LUA"
+ - task_with_group_result.principal.user_id == None
+
+- name: task with group principal (idempotent)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ group: Administrators
+ logon_type: group
+ actions:
+ - path: cmd.exe
+ register: task_with_group_again
+
+- name: assert results of task with group principal (idempotent)
+ assert:
+ that:
+ - task_with_group_again is not changed
+
+- name: task with service account principal (check mode)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ username: System
+ logon_type: service_account
+ action:
+ - path: cmd.exe
+ register: task_with_service_check
+ check_mode: yes
+
+- name: get result of task with service account principal (check mode)
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: task_with_service_result_check
+
+- name: assert results of task with service account principal (check mode)
+ assert:
+ that:
+ - task_with_service_check is changed
+ - task_with_service_result_check.task_exists == True
+ - task_with_service_result_check.principal.group_id == "BUILTIN\\Administrators"
+ - task_with_service_result_check.principal.logon_type == "TASK_LOGON_GROUP"
+ - task_with_service_result_check.principal.run_level == "TASK_RUNLEVEL_LUA"
+ - task_with_service_result_check.principal.user_id == None
+
+- name: task with service account principal
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ username: System
+ logon_type: service_account
+ action:
+ - path: cmd.exe
+ register: task_with_service
+
+- name: get result of task with service account principal
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: task_with_service_result
+
+- name: assert results of task with service account principal
+ assert:
+ that:
+ - task_with_service is changed
+ - task_with_service_result.task_exists == True
+ - task_with_service_result.principal.group_id == None
+ - task_with_service_result.principal.logon_type == "TASK_LOGON_SERVICE_ACCOUNT"
+ - task_with_service_result.principal.run_level == "TASK_RUNLEVEL_LUA"
+ - task_with_service_result.principal.user_id == "NT AUTHORITY\\SYSTEM"
+
+- name: task with service account principal (idempotent)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ username: System
+ logon_type: service_account
+ action:
+ - path: cmd.exe
+ register: task_with_service_again
+
+- name: assert results of task with service account principal (idempotent)
+ assert:
+ that:
+ - task_with_service_again is not changed
+
+- name: task with highest privilege (check mode)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ run_level: highest
+ username: System
+ logon_type: service_account
+ action:
+ - path: cmd.exe
+ register: task_with_highest_privilege_check
+ check_mode: yes
+
+- name: get result of task with highest privilege (check mode)
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: task_with_highest_privilege_result_check
+
+- name: assert results of task with highest privilege (check mode)
+ assert:
+ that:
+ - task_with_highest_privilege_check is changed
+ - task_with_highest_privilege_result_check.principal.run_level == "TASK_RUNLEVEL_LUA"
+
+- name: task with highest privilege
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ run_level: highest
+ username: System
+ logon_type: service_account
+ action:
+ - path: cmd.exe
+ register: task_with_highest_privilege
+
+- name: get result of task with highest privilege
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: task_with_highest_privilege_result
+
+- name: assert results of task with highest privilege
+ assert:
+ that:
+ - task_with_highest_privilege is changed
+ - task_with_highest_privilege_result.principal.run_level == "TASK_RUNLEVEL_HIGHEST"
+
+- name: task with highest privilege (idempotent)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ run_level: highest
+ username: System
+ logon_type: service_account
+ action:
+ - path: cmd.exe
+ register: task_with_highest_privilege_again
+
+- name: assert results of task with highest privilege (idempotent)
+ assert:
+ that:
+ - task_with_highest_privilege_again is not changed
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/tasks/tests.yml
new file mode 100644
index 000000000..b4ed29e49
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/tasks/tests.yml
@@ -0,0 +1,440 @@
+---
+- name: create task (check mode)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ arguments: /c echo hi
+ description: Original Description
+ register: create_task_check
+ check_mode: yes
+
+- name: get result of create task (check mode)
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: create_task_result_check
+
+- name: assert results of create task (check mode)
+ assert:
+ that:
+ - create_task_check is changed
+ - create_task_result_check.task_exists == False
+
+- name: create task
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ arguments: /c echo hi
+ description: Original Description
+ register: create_task
+
+- name: get result of create task
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: create_task_result
+
+- name: assert results of create task
+ assert:
+ that:
+ - create_task is changed
+ - create_task_result.task_exists == True
+ - create_task_result.actions|count == 1
+ - create_task_result.actions[0].path == "cmd.exe"
+ - create_task_result.actions[0].arguments == "/c echo hi"
+ - create_task_result.actions[0].working_directory == None
+ - create_task_result.registration_info.description == "Original Description"
+ - create_task_result.triggers|count == 0
+
+- name: create task (idempotent)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ arguments: /c echo hi
+ description: Original Description
+ register: create_task_again
+
+- name: assert results of create task (idempotent)
+ assert:
+ that:
+ - create_task_again is not changed
+
+- name: change task (check mode)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ author: Cow Inc.
+ description: Test for Ansible
+ allow_demand_start: no
+ restart_count: 5
+ restart_interval: PT2H5M
+ register: change_task_check
+ check_mode: yes
+
+- name: get result of change task (check mode)
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: change_task_result_check
+
+- name: assert results of change task (check mode)
+ assert:
+ that:
+ - change_task_check is changed
+ - change_task_result_check.actions|count == 1
+ - change_task_result_check.registration_info.author == None
+ - change_task_result_check.registration_info.description == "Original Description"
+ - change_task_result_check.settings.allow_demand_start == true
+ - change_task_result_check.settings.restart_count == 0
+ - change_task_result_check.settings.restart_interval == None
+
+- name: change task
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ author: Cow Inc.
+ description: Test for Ansible
+ allow_demand_start: no
+ restart_count: 5
+ restart_interval: PT1M
+ register: change_task
+
+- name: get result of change task
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: change_task_result
+
+- name: assert results of change task
+ assert:
+ that:
+ - change_task is changed
+ - change_task_result.actions|count == 1
+ - change_task_result.registration_info.author == "Cow Inc."
+ - change_task_result.registration_info.description == "Test for Ansible"
+ - change_task_result.settings.allow_demand_start == false
+ - change_task_result.settings.restart_count == 5
+ - change_task_result.settings.restart_interval == "PT1M"
+
+- name: change task (idempotent)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ author: Cow Inc.
+ description: Test for Ansible
+ allow_demand_start: no
+ restart_count: 5
+ restart_interval: PT1M
+ register: change_task_again
+
+- name: assert results of change task (idempotent)
+ assert:
+ that:
+ - change_task_again is not changed
+
+- name: add task action (check mode)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ arguments: /c echo hi
+ - path: powershell.exe
+ arguments: -File C:\ansible\script.ps1
+ working_directory: C:\ansible
+ register: add_task_action_check
+ check_mode: yes
+
+- name: get result of add task action (check mode)
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: add_task_action_result_check
+
+- name: assert results of add task action (check mode)
+ assert:
+ that:
+ - add_task_action_check is changed
+ - add_task_action_result_check.actions|count == 1
+ - add_task_action_result_check.actions[0].path == "cmd.exe"
+ - add_task_action_result_check.actions[0].arguments == "/c echo hi"
+ - add_task_action_result_check.actions[0].working_directory == None
+
+- name: add task action
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ arguments: /c echo hi
+ - path: powershell.exe
+ arguments: -File C:\ansible\script.ps1
+ working_directory: C:\ansible
+ register: add_task_action
+
+- name: get result of add task action
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: add_task_action_result
+
+- name: assert results of add task action
+ assert:
+ that:
+ - add_task_action is changed
+ - add_task_action_result.actions|count == 2
+ - add_task_action_result.actions[0].path == "cmd.exe"
+ - add_task_action_result.actions[0].arguments == "/c echo hi"
+ - add_task_action_result.actions[0].working_directory == None
+ - add_task_action_result.actions[1].path == "powershell.exe"
+ - add_task_action_result.actions[1].arguments == "-File C:\\ansible\\script.ps1"
+ - add_task_action_result.actions[1].working_directory == "C:\\ansible"
+
+- name: add task action (idempotent)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ arguments: /c echo hi
+ - path: powershell.exe
+ arguments: -File C:\ansible\script.ps1
+ working_directory: C:\ansible
+ register: add_task_action_again
+
+- name: assert results of add task action (idempotent)
+ assert:
+ that:
+ - add_task_action_again is not changed
+
+- name: remove task action (check mode)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: powershell.exe
+ arguments: -File C:\ansible\script.ps1
+ working_directory: C:\ansible
+ register: remove_task_action_check
+ check_mode: yes
+
+- name: get result of remove task action (check mode)
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: remove_task_action_result_check
+
+- name: assert results of remove task action (check mode)
+ assert:
+ that:
+ - remove_task_action_check is changed
+ - remove_task_action_result_check.actions|count == 2
+ - remove_task_action_result_check.actions[0].path == "cmd.exe"
+ - remove_task_action_result_check.actions[0].arguments == "/c echo hi"
+ - remove_task_action_result_check.actions[0].working_directory == None
+ - remove_task_action_result_check.actions[1].path == "powershell.exe"
+ - remove_task_action_result_check.actions[1].arguments == "-File C:\\ansible\\script.ps1"
+ - remove_task_action_result_check.actions[1].working_directory == "C:\\ansible"
+
+- name: remove task action
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: powershell.exe
+ arguments: -File C:\ansible\script.ps1
+ working_directory: C:\ansible
+ register: remove_task_action
+
+- name: get result of remove task action
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: remove_task_action_result
+
+- name: assert results of remove task action
+ assert:
+ that:
+ - remove_task_action is changed
+ - remove_task_action_result.actions|count == 1
+ - remove_task_action_result.actions[0].path == "powershell.exe"
+ - remove_task_action_result.actions[0].arguments == "-File C:\\ansible\\script.ps1"
+ - remove_task_action_result.actions[0].working_directory == "C:\\ansible"
+
+- name: remove task action (idempontent)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: powershell.exe
+ arguments: -File C:\ansible\script.ps1
+ working_directory: C:\ansible
+ register: remove_task_action_again
+
+- name: assert results of remove task action (idempotent)
+ assert:
+ that:
+ - remove_task_action_again is not changed
+
+- name: remove task (check mode)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: absent
+ register: remove_task_check
+ check_mode: yes
+
+- name: get result of remove task (check mode)
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: remove_task_result_check
+
+- name: assert results of remove task (check mode)
+ assert:
+ that:
+ - remove_task_check is changed
+ - remove_task_result_check.task_exists == True
+
+- name: remove task
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: absent
+ register: remove_task
+
+- name: get result of remove task
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: remove_task_result
+
+- name: assert results of remove task
+ assert:
+ that:
+ - remove_task is changed
+ - remove_task_result.task_exists == False
+
+- name: remove task (idempotent)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: absent
+ register: remove_task_again
+
+- name: assert results of remove task (idempotent)
+ assert:
+ that:
+ - remove_task_again is not changed
+
+- name: create sole task in folder (check mode)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ path: '{{test_scheduled_task_path}}'
+ actions:
+ - path: cmd.exe
+ register: create_sole_task_check
+ check_mode: yes
+
+- name: get result of create sole task in folder (check mode)
+ win_scheduled_task_stat:
+ path: '{{test_scheduled_task_path}}'
+ name: '{{test_scheduled_task_name}}'
+ register: create_sole_task_result_check
+
+- name: assert results of create sole task in folder (check mode)
+ assert:
+ that:
+ - create_sole_task_check is changed
+ - create_sole_task_result_check.folder_exists == False
+ - create_sole_task_result_check.task_exists == False
+
+- name: create sole task in folder
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ path: '{{test_scheduled_task_path}}'
+ actions:
+ - path: cmd.exe
+ register: create_sole_task
+
+- name: get result of create sole task in folder
+ win_scheduled_task_stat:
+ path: '{{test_scheduled_task_path}}'
+ name: '{{test_scheduled_task_name}}'
+ register: create_sole_task_result
+
+- name: assert results of create sole task in folder
+ assert:
+ that:
+ - create_sole_task is changed
+ - create_sole_task_result.folder_exists == True
+ - create_sole_task_result.task_exists == True
+
+- name: create sole task in folder (idempotent)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ path: '{{test_scheduled_task_path}}'
+ actions:
+ - path: cmd.exe
+ register: create_sole_task_again
+
+- name: assert results of create sole task in folder (idempotent)
+ assert:
+ that:
+ - create_sole_task_again is not changed
+
+- name: remove sole task in folder (check mode)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ path: '{{test_scheduled_task_path}}'
+ state: absent
+ register: remove_sole_task_check
+ check_mode: yes
+
+- name: get result of remove sole task in folder (check mode)
+ win_scheduled_task_stat:
+ path: '{{test_scheduled_task_path}}'
+ name: '{{test_scheduled_task_name}}'
+ register: remove_sole_task_result_check
+
+- name: assert results of remove sole task in folder (check mode)
+ assert:
+ that:
+ - remove_sole_task_check is changed
+ - remove_sole_task_result_check.folder_exists == True
+ - remove_sole_task_result_check.task_exists == True
+
+- name: remove sole task in folder
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ path: '{{test_scheduled_task_path}}'
+ state: absent
+ register: remove_sole_task
+
+- name: get result of remove sole task in folder
+ win_scheduled_task_stat:
+ path: '{{test_scheduled_task_path}}'
+ name: '{{test_scheduled_task_name}}'
+ register: remove_sole_task_result
+
+- name: assert results of remove sole task in folder
+ assert:
+ that:
+ - remove_sole_task is changed
+ - remove_sole_task_result.folder_exists == False
+ - remove_sole_task_result.task_exists == False
+
+- name: remove sole task in folder (idempotent)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ path: '{{test_scheduled_task_path}}'
+ state: absent
+ register: remove_sole_task_again
+
+- name: assert results of remove sole task in folder (idempotent)
+ assert:
+ that:
+ - remove_sole_task_again is not changed
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/tasks/triggers.yml b/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/tasks/triggers.yml
new file mode 100644
index 000000000..eae42c98a
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/tasks/triggers.yml
@@ -0,0 +1,851 @@
+---
+- name: create boot trigger (check mode)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ triggers:
+ - type: boot
+ register: trigger_boot_check
+ check_mode: yes
+
+- name: get result of create boot trigger (check mode)
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: trigger_boot_result_check
+
+- name: assert results of create boot trigger (check mode)
+ assert:
+ that:
+ - trigger_boot_check is changed
+ - trigger_boot_result_check.task_exists == False
+
+- name: create boot trigger
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ triggers:
+ - type: boot
+ register: trigger_boot
+
+- name: get result of create boot trigger
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: trigger_boot_result
+
+- name: assert results of create boot trigger
+ assert:
+ that:
+ - trigger_boot is changed
+ - trigger_boot_result.task_exists == True
+ - trigger_boot_result.triggers|count == 1
+ - trigger_boot_result.triggers[0].type == "TASK_TRIGGER_BOOT"
+ - trigger_boot_result.triggers[0].enabled == True
+ - trigger_boot_result.triggers[0].start_boundary == None
+ - trigger_boot_result.triggers[0].end_boundary == None
+
+- name: create boot trigger (idempotent)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ triggers:
+ - type: boot
+ register: trigger_boot_again
+
+- name: assert results of create boot trigger (idempotent)
+ assert:
+ that:
+ - trigger_boot_again is not changed
+
+- name: create daily trigger (check mode)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ triggers:
+ - type: daily
+ start_boundary: '2000-01-01T00:00:01'
+ register: trigger_daily_check
+ check_mode: yes
+
+- name: get result of create daily trigger (check mode)
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: trigger_daily_result_check
+
+- name: assert results of create daily trigger (check mode)
+ assert:
+ that:
+ - trigger_daily_check is changed
+ - trigger_daily_result_check.task_exists == True
+ - trigger_daily_result_check.triggers|count == 1
+ - trigger_daily_result_check.triggers[0].type == "TASK_TRIGGER_BOOT"
+ - trigger_daily_result_check.triggers[0].enabled == True
+ - trigger_daily_result_check.triggers[0].start_boundary == None
+ - trigger_daily_result_check.triggers[0].end_boundary == None
+
+- name: create daily trigger
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ triggers:
+ - type: daily
+ start_boundary: '2000-01-01T00:00:01'
+ register: trigger_daily
+
+- name: get result of create daily trigger
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: trigger_daily_result
+
+- name: assert results of create daily trigger
+ assert:
+ that:
+ - trigger_daily is changed
+ - trigger_daily_result.task_exists == True
+ - trigger_daily_result.triggers|count == 1
+ - trigger_daily_result.triggers[0].type == "TASK_TRIGGER_DAILY"
+ - trigger_daily_result.triggers[0].enabled == True
+ - trigger_daily_result.triggers[0].start_boundary == "2000-01-01T00:00:01"
+ - trigger_daily_result.triggers[0].end_boundary == None
+
+- name: create daily trigger (idempotent)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ triggers:
+ - type: daily
+ start_boundary: '2000-01-01T00:00:01'
+ register: trigger_daily_again
+
+- name: assert results of create daily trigger (idempotent)
+ assert:
+ that:
+ - trigger_daily_again is not changed
+
+- name: create logon trigger (check mode)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ triggers:
+ - type: logon
+ register: trigger_logon_check
+ check_mode: yes
+
+- name: get result of create logon trigger (check mode)
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: trigger_logon_result_check
+
+- name: assert results of create logon trigger
+ assert:
+ that:
+ - trigger_logon_check is changed
+ - trigger_logon_result_check.task_exists == True
+ - trigger_logon_result_check.triggers|count == 1
+ - trigger_logon_result_check.triggers[0].type == "TASK_TRIGGER_DAILY"
+ - trigger_logon_result_check.triggers[0].enabled == True
+ - trigger_logon_result_check.triggers[0].start_boundary == "2000-01-01T00:00:01"
+ - trigger_logon_result_check.triggers[0].end_boundary == None
+
+- name: create logon trigger
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ triggers:
+ - type: logon
+ register: trigger_logon
+
+- name: get result of create logon trigger
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: trigger_logon_result
+
+- name: assert results of create logon trigger
+ assert:
+ that:
+ - trigger_logon is changed
+ - trigger_logon_result.task_exists == True
+ - trigger_logon_result.triggers|count == 1
+ - trigger_logon_result.triggers[0].type == "TASK_TRIGGER_LOGON"
+ - trigger_logon_result.triggers[0].enabled == True
+ - trigger_logon_result.triggers[0].start_boundary == None
+ - trigger_logon_result.triggers[0].end_boundary == None
+
+- name: create logon trigger (idempotent)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ triggers:
+ - type: logon
+ register: trigger_logon_again
+
+- name: assert results of create logon trigger (idempotent)
+ assert:
+ that:
+ - trigger_logon_again is not changed
+
+- name: create monthly dow trigger (check mode)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ triggers:
+ - type: monthlydow
+ start_boundary: '2000-01-01T00:00:01'
+ weeks_of_month: 1,2
+ run_on_last_week_of_month: true
+ days_of_week: [ "monday", "wednesday" ]
+ register: trigger_monthlydow_check
+ check_mode: yes
+
+- name: get result of create monthly dow trigger (check mode)
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: trigger_monthlydow_result_check
+
+- name: assert results of create monthly dow trigger (check mode)
+ assert:
+ that:
+ - trigger_monthlydow_check is changed
+ - trigger_monthlydow_result_check.task_exists == True
+ - trigger_monthlydow_result_check.triggers|count == 1
+ - trigger_monthlydow_result_check.triggers[0].type == "TASK_TRIGGER_LOGON"
+ - trigger_monthlydow_result_check.triggers[0].enabled == True
+ - trigger_monthlydow_result_check.triggers[0].start_boundary == None
+ - trigger_monthlydow_result_check.triggers[0].end_boundary == None
+
+- name: create monthly dow trigger
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ triggers:
+ - type: monthlydow
+ start_boundary: '2000-01-01T00:00:01+03:00'
+ weeks_of_month: 1,2
+ run_on_last_week_of_month: true
+ days_of_week: [ "monday", "wednesday" ]
+ register: trigger_monthlydow
+
+- name: get result of create monthly dow trigger
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: trigger_monthlydow_result
+
+- name: get expected date based on host timezone
+ ansible.windows.win_shell: (Get-Date '1999-12-31T21:00:01+00:00').ToString('yyyy-MM-ddTHH:mm:sszzz')
+ register: trigger_monthlydow_date
+
+- name: assert results of create monthly dow trigger
+ assert:
+ that:
+ - trigger_monthlydow is changed
+ - trigger_monthlydow_result.task_exists == True
+ - trigger_monthlydow_result.triggers|count == 1
+ - trigger_monthlydow_result.triggers[0].type == "TASK_TRIGGER_MONTHLYDOW"
+ - trigger_monthlydow_result.triggers[0].enabled == True
+ - trigger_monthlydow_result.triggers[0].start_boundary == trigger_monthlydow_date.stdout|trim
+ - trigger_monthlydow_result.triggers[0].end_boundary == None
+ - trigger_monthlydow_result.triggers[0].weeks_of_month == "1,2"
+ - trigger_monthlydow_result.triggers[0].run_on_last_week_of_month == True
+ - trigger_monthlydow_result.triggers[0].days_of_week == "monday,wednesday"
+
+- name: create monthly dow trigger (idempotent)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ triggers:
+ - type: monthlydow
+ start_boundary: '2000-01-01T00:00:01+03:00'
+ weeks_of_month: 1,2
+ run_on_last_week_of_month: true
+ days_of_week: [ "monday", "wednesday" ]
+ register: trigger_monthlydow_again
+
+- name: assert results of create monthly dow trigger (idempotent)
+ assert:
+ that:
+ - trigger_monthlydow_again is not changed
+
+- name: create trigger repetition (check mode)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ triggers:
+ - type: registration
+ repetition:
+ # TODO: change to dict in 2.12 as a list format is deprecated
+ - interval: PT1M
+ duration: PT5M
+ stop_at_duration_end: yes
+ register: create_trigger_repetition_check
+ check_mode: yes
+
+- name: get result of create trigger repetition (check mode)
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: create_trigger_repetition_result_check
+
+- name: assert results of create trigger repetition (check mode)
+ assert:
+ that:
+ - create_trigger_repetition_check is changed
+ - create_trigger_repetition_check.deprecations|count == 1
+ - create_trigger_repetition_check.deprecations[0].date == "2021-07-01"
+ - create_trigger_repetition_check.deprecations[0].msg == "repetition is a list, should be defined as a dict"
+ - create_trigger_repetition_result_check.task_exists == True
+ - create_trigger_repetition_result_check.triggers|count == 1
+ - create_trigger_repetition_result_check.triggers[0].type == "TASK_TRIGGER_MONTHLYDOW"
+ - create_trigger_repetition_result_check.triggers[0].enabled == True
+ - create_trigger_repetition_result_check.triggers[0].start_boundary == trigger_monthlydow_date.stdout|trim
+ - create_trigger_repetition_result_check.triggers[0].end_boundary == None
+ - create_trigger_repetition_result_check.triggers[0].weeks_of_month == "1,2"
+ - create_trigger_repetition_result_check.triggers[0].run_on_last_week_of_month == True
+ - create_trigger_repetition_result_check.triggers[0].days_of_week == "monday,wednesday"
+ - create_trigger_repetition_result_check.triggers[0].repetition.interval == None
+ - create_trigger_repetition_result_check.triggers[0].repetition.duration == None
+ - create_trigger_repetition_result_check.triggers[0].repetition.stop_at_duration_end == False
+
+- name: create trigger repetition
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ triggers:
+ - type: registration
+ repetition:
+ interval: PT1M
+ duration: PT5M
+ stop_at_duration_end: yes
+ register: create_trigger_repetition
+
+- name: get result of create trigger repetition
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: create_trigger_repetition_result
+
+- name: assert results of create trigger repetition
+ assert:
+ that:
+ - create_trigger_repetition is changed
+ - create_trigger_repetition_result.task_exists == True
+ - create_trigger_repetition_result.triggers|count == 1
+ - create_trigger_repetition_result.triggers[0].type == "TASK_TRIGGER_REGISTRATION"
+ - create_trigger_repetition_result.triggers[0].enabled == True
+ - create_trigger_repetition_result.triggers[0].start_boundary == None
+ - create_trigger_repetition_result.triggers[0].end_boundary == None
+ - create_trigger_repetition_result.triggers[0].repetition.interval == "PT1M"
+ - create_trigger_repetition_result.triggers[0].repetition.duration == "PT5M"
+ - create_trigger_repetition_result.triggers[0].repetition.stop_at_duration_end == True
+
+- name: create trigger repetition (idempotent)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ triggers:
+ - type: registration
+ repetition:
+ interval: PT1M
+ duration: PT5M
+ stop_at_duration_end: yes
+ register: create_trigger_repetition_again
+
+- name: assert results of create trigger repetition (idempotent)
+ assert:
+ that:
+ - create_trigger_repetition_again is not changed
+
+- name: change trigger repetition (check mode)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ triggers:
+ - type: registration
+ repetition:
+ interval: PT10M
+ duration: PT20M
+ stop_at_duration_end: no
+ register: change_trigger_repetition_check
+ check_mode: yes
+
+- name: get result of change trigger repetition (check mode)
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: change_trigger_repetition_result_check
+
+- name: assert results of change trigger repetition (check mode)
+ assert:
+ that:
+ - change_trigger_repetition_check is changed
+ - change_trigger_repetition_result_check.task_exists == True
+ - change_trigger_repetition_result_check.triggers|count == 1
+ - change_trigger_repetition_result_check.triggers[0].type == "TASK_TRIGGER_REGISTRATION"
+ - change_trigger_repetition_result_check.triggers[0].enabled == True
+ - change_trigger_repetition_result_check.triggers[0].start_boundary == None
+ - change_trigger_repetition_result_check.triggers[0].end_boundary == None
+ - change_trigger_repetition_result_check.triggers[0].repetition.interval == "PT1M"
+ - change_trigger_repetition_result_check.triggers[0].repetition.duration == "PT5M"
+ - change_trigger_repetition_result_check.triggers[0].repetition.stop_at_duration_end == True
+
+- name: change trigger repetition
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ triggers:
+ - type: registration
+ repetition:
+ interval: PT10M
+ duration: PT20M
+ stop_at_duration_end: no
+ register: change_trigger_repetition
+
+- name: get result of change trigger repetition
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: change_trigger_repetition_result
+
+- name: assert results of change trigger repetition
+ assert:
+ that:
+ - change_trigger_repetition is changed
+ - change_trigger_repetition_result.task_exists == True
+ - change_trigger_repetition_result.triggers|count == 1
+ - change_trigger_repetition_result.triggers[0].type == "TASK_TRIGGER_REGISTRATION"
+ - change_trigger_repetition_result.triggers[0].enabled == True
+ - change_trigger_repetition_result.triggers[0].start_boundary == None
+ - change_trigger_repetition_result.triggers[0].end_boundary == None
+ - change_trigger_repetition_result.triggers[0].repetition.interval == "PT10M"
+ - change_trigger_repetition_result.triggers[0].repetition.duration == "PT20M"
+ - change_trigger_repetition_result.triggers[0].repetition.stop_at_duration_end == False
+
+- name: change trigger repetition (idempotent)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ triggers:
+ - type: registration
+ repetition:
+ interval: PT10M
+ duration: PT20M
+ stop_at_duration_end: no
+ register: change_trigger_repetition_again
+
+- name: assert results of change trigger repetition (idempotent)
+ assert:
+ that:
+ - change_trigger_repetition_again is not changed
+
+- name: create trigger with state_change
+ win_scheduled_task:
+ name: '{{ test_scheduled_task_name }}'
+ state: present
+ actions:
+ - path: cmd.exe
+ triggers:
+ - type: session_state_change
+ state_change: session_lock
+ register: trigger_state_change
+
+- name: get result of create trigger with state change
+ win_scheduled_task_stat:
+ path: \
+ name: '{{ test_scheduled_task_name }}'
+ register: trigger_state_change_result
+
+- name: assert results of create trigger with state_change
+ assert:
+ that:
+ - trigger_state_change is changed
+ - trigger_state_change_result.triggers|count == 1
+ - trigger_state_change_result.triggers[0].type == "TASK_TRIGGER_SESSION_STATE_CHANGE"
+ - trigger_state_change_result.triggers[0].state_change == 7
+ - trigger_state_change_result.triggers[0].state_change_str == "TASK_SESSION_LOCK"
+ - trigger_state_change_result.triggers[0].user_id == None
+
+- name: create task with multiple triggers (check mode)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ triggers:
+ - type: monthly
+ days_of_month: 1,5,10,15,20,25,30
+ run_on_last_day_of_month: true
+ start_boundary: '2000-01-01T00:00:01'
+ months_of_year:
+ - march
+ - may
+ - july
+ - type: time
+ start_boundary: '2000-01-01T00:00:01'
+ random_delay: PT10M5S
+ register: create_multiple_triggers_check
+ check_mode: yes
+
+- name: get result of create task with multiple triggers (check mode)
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: create_multiple_triggers_result_check
+
+- name: assert results of create task with multiple triggers (check mode)
+ assert:
+ that:
+ - create_multiple_triggers_check is changed
+ - create_multiple_triggers_result_check.task_exists == True
+ - create_multiple_triggers_result_check.triggers|count == 1
+ - create_multiple_triggers_result_check.triggers[0].type == "TASK_TRIGGER_SESSION_STATE_CHANGE"
+ - create_multiple_triggers_result_check.triggers[0].state_change == 7
+ - create_multiple_triggers_result_check.triggers[0].state_change_str == "TASK_SESSION_LOCK"
+ - create_multiple_triggers_result_check.triggers[0].user_id == None
+
+- name: create task with multiple triggers
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ triggers:
+ - type: monthly
+ days_of_month: 1,5,10,15,20,25,30
+ run_on_last_day_of_month: true
+ start_boundary: '2000-01-01T00:00:01'
+ months_of_year:
+ - march
+ - may
+ - july
+ - type: time
+ start_boundary: '2000-01-01T00:00:01'
+ random_delay: PT10M5S
+ register: create_multiple_triggers
+
+- name: get result of create task with multiple triggers
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: create_multiple_triggers_result
+
+- name: assert results of create task with multiple triggers
+ assert:
+ that:
+ - create_multiple_triggers is changed
+ - create_multiple_triggers_result.task_exists == True
+ - create_multiple_triggers_result.triggers|count == 2
+ - create_multiple_triggers_result.triggers[0].type == "TASK_TRIGGER_MONTHLY"
+ - create_multiple_triggers_result.triggers[0].enabled == True
+ - create_multiple_triggers_result.triggers[0].start_boundary == "2000-01-01T00:00:01"
+ - create_multiple_triggers_result.triggers[0].end_boundary == None
+ - create_multiple_triggers_result.triggers[0].days_of_month == "1,5,10,15,20,25,30"
+ - create_multiple_triggers_result.triggers[0].months_of_year == "march,may,july"
+ - create_multiple_triggers_result.triggers[0].run_on_last_day_of_month == True
+ - create_multiple_triggers_result.triggers[1].type == "TASK_TRIGGER_TIME"
+ - create_multiple_triggers_result.triggers[1].enabled == True
+ - create_multiple_triggers_result.triggers[1].start_boundary == "2000-01-01T00:00:01"
+ - create_multiple_triggers_result.triggers[1].end_boundary == None
+ - create_multiple_triggers_result.triggers[1].random_delay == "PT10M5S"
+
+- name: create task with multiple triggers (idempotent)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ triggers:
+ - type: monthly
+ days_of_month: 1,5,10,15,20,25,30
+ run_on_last_day_of_month: true
+ start_boundary: '2000-01-01T00:00:01'
+ months_of_year:
+ - march
+ - may
+ - july
+ - type: time
+ start_boundary: '2000-01-01T00:00:01'
+ random_delay: PT10M5S
+ register: create_multiple_triggers_again
+
+- name: assert results of create task with multiple triggers (idempotent)
+ assert:
+ that:
+ - create_multiple_triggers_again is not changed
+
+- name: change task with multiple triggers (check mode)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ triggers:
+ - type: weekly
+ days_of_week: tuesday,friday
+ start_boundary: '2000-01-01T00:00:01'
+ - type: registration
+ enabled: no
+ register: change_multiple_triggers_check
+ check_mode: yes
+
+- name: get result of change task with multiple triggers (check mode)
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: change_multiple_triggers_result_check
+
+- name: assert results of change task with multiple triggers (check mode)
+ assert:
+ that:
+ - change_multiple_triggers_check is changed
+ - change_multiple_triggers_result_check.task_exists == True
+ - change_multiple_triggers_result_check.triggers|count == 2
+ - change_multiple_triggers_result_check.triggers[0].type == "TASK_TRIGGER_MONTHLY"
+ - change_multiple_triggers_result_check.triggers[0].enabled == True
+ - change_multiple_triggers_result_check.triggers[0].start_boundary == "2000-01-01T00:00:01"
+ - change_multiple_triggers_result_check.triggers[0].end_boundary == None
+ - change_multiple_triggers_result_check.triggers[0].days_of_month == "1,5,10,15,20,25,30"
+ - change_multiple_triggers_result_check.triggers[0].months_of_year == "march,may,july"
+ - change_multiple_triggers_result_check.triggers[0].run_on_last_day_of_month == True
+ - change_multiple_triggers_result_check.triggers[1].type == "TASK_TRIGGER_TIME"
+ - change_multiple_triggers_result_check.triggers[1].enabled == True
+ - change_multiple_triggers_result_check.triggers[1].start_boundary == "2000-01-01T00:00:01"
+ - change_multiple_triggers_result_check.triggers[1].end_boundary == None
+ - change_multiple_triggers_result_check.triggers[1].random_delay == "PT10M5S"
+
+- name: change task with multiple triggers
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ triggers:
+ - type: weekly
+ days_of_week: tuesday,friday
+ start_boundary: '2000-01-01T00:00:01'
+ - type: registration
+ enabled: no
+ register: change_multiple_triggers
+
+- name: get result of change task with multiple triggers
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: change_multiple_triggers_result
+
+- name: assert results of change task with multiple triggers
+ assert:
+ that:
+ - change_multiple_triggers is changed
+ - change_multiple_triggers_result.task_exists == True
+ - change_multiple_triggers_result.triggers|count == 2
+ - change_multiple_triggers_result.triggers[0].type == "TASK_TRIGGER_WEEKLY"
+ - change_multiple_triggers_result.triggers[0].enabled == True
+ - change_multiple_triggers_result.triggers[0].start_boundary == "2000-01-01T00:00:01"
+ - change_multiple_triggers_result.triggers[0].end_boundary == None
+ - change_multiple_triggers_result.triggers[0].days_of_week == "tuesday,friday"
+ - change_multiple_triggers_result.triggers[1].type == "TASK_TRIGGER_REGISTRATION"
+ - change_multiple_triggers_result.triggers[1].enabled == False
+ - change_multiple_triggers_result.triggers[1].start_boundary == None
+ - change_multiple_triggers_result.triggers[1].end_boundary == None
+
+- name: change task with multiple triggers (idempotent)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ triggers:
+ - type: weekly
+ days_of_week: tuesday,friday
+ start_boundary: '2000-01-01T00:00:01'
+ - type: registration
+ enabled: no
+ register: change_multiple_triggers_again
+
+- name: assert results of change task with multiple triggers (idempotent)
+ assert:
+ that:
+ - change_multiple_triggers_again is not changed
+
+- name: remove trigger from multiple triggers (check mode)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ triggers:
+ - type: registration
+ enabled: no
+ register: remove_single_trigger_check
+ check_mode: yes
+
+- name: get result of remove trigger from multiple triggers (check mode)
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: remove_single_trigger_result_check
+
+- name: assert results of remove trigger from multiple triggers (check mode)
+ assert:
+ that:
+ - remove_single_trigger_check is changed
+ - remove_single_trigger_result_check.task_exists == True
+ - remove_single_trigger_result_check.triggers|count == 2
+ - remove_single_trigger_result_check.triggers[0].type == "TASK_TRIGGER_WEEKLY"
+ - remove_single_trigger_result_check.triggers[0].enabled == True
+ - remove_single_trigger_result_check.triggers[0].start_boundary == "2000-01-01T00:00:01"
+ - remove_single_trigger_result_check.triggers[0].end_boundary == None
+ - remove_single_trigger_result_check.triggers[0].days_of_week == "tuesday,friday"
+ - remove_single_trigger_result_check.triggers[1].type == "TASK_TRIGGER_REGISTRATION"
+ - remove_single_trigger_result_check.triggers[1].enabled == False
+ - remove_single_trigger_result_check.triggers[1].start_boundary == None
+ - remove_single_trigger_result_check.triggers[1].end_boundary == None
+
+- name: remove trigger from multiple triggers
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ triggers:
+ - type: registration
+ enabled: no
+ register: remove_single_trigger
+
+- name: get result of remove trigger from multiple triggers
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: remove_single_trigger_result
+
+- name: assert results of remove trigger from multiple triggers
+ assert:
+ that:
+ - remove_single_trigger is changed
+ - remove_single_trigger_result.task_exists == True
+ - remove_single_trigger_result.triggers|count == 1
+ - remove_single_trigger_result.triggers[0].type == "TASK_TRIGGER_REGISTRATION"
+ - remove_single_trigger_result.triggers[0].enabled == False
+ - remove_single_trigger_result.triggers[0].start_boundary == None
+ - remove_single_trigger_result.triggers[0].end_boundary == None
+
+- name: remove trigger from multiple triggers (idempotent)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ triggers:
+ - type: registration
+ enabled: no
+ register: remove_single_trigger_again
+
+- name: assert results of remove trigger from multiple triggers (idempotent)
+ assert:
+ that:
+ - remove_single_trigger_again is not changed
+
+- name: remove all triggers (check mode)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ triggers: []
+ register: remove_triggers_check
+ check_mode: yes
+
+- name: get result of remove all triggers (check mode)
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: remove_triggers_result_check
+
+- name: assert results of remove all triggers (check mode)
+ assert:
+ that:
+ - remove_triggers_check is changed
+ - remove_triggers_result_check.task_exists == True
+ - remove_triggers_result_check.triggers|count == 1
+ - remove_triggers_result_check.triggers[0].type == "TASK_TRIGGER_REGISTRATION"
+ - remove_triggers_result_check.triggers[0].enabled == False
+ - remove_triggers_result_check.triggers[0].start_boundary == None
+ - remove_triggers_result_check.triggers[0].end_boundary == None
+
+- name: remove all triggers
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ triggers: []
+ register: remove_triggers
+
+- name: get result of remove all triggers
+ win_scheduled_task_stat:
+ path: \
+ name: '{{test_scheduled_task_name}}'
+ register: remove_triggers_result
+
+- name: assert results of remove all triggers
+ assert:
+ that:
+ - remove_triggers is changed
+ - remove_triggers_result.task_exists == True
+ - remove_triggers_result.triggers|count == 0
+
+- name: remove all triggers (idempotent)
+ win_scheduled_task:
+ name: '{{test_scheduled_task_name}}'
+ state: present
+ actions:
+ - path: cmd.exe
+ triggers: []
+ register: remove_triggers_again
+
+- name: assert results of remove all triggers (idempotent)
+ assert:
+ that:
+ - remove_triggers_again is not changed
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task_stat/aliases b/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task_stat/aliases
new file mode 100644
index 000000000..423ce3910
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task_stat/aliases
@@ -0,0 +1 @@
+shippable/windows/group2
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task_stat/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task_stat/defaults/main.yml
new file mode 100644
index 000000000..55a2b87b3
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task_stat/defaults/main.yml
@@ -0,0 +1,5 @@
+---
+test_scheduled_task_stat_name: Test Task
+test_scheduled_task_stat_path: \test path
+test_scheduled_task_stat_username: testtaskuser
+test_scheduled_task_stat_password: Password123! \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task_stat/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task_stat/tasks/main.yml
new file mode 100644
index 000000000..736899487
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task_stat/tasks/main.yml
@@ -0,0 +1,47 @@
+---
+- name: ensure task is deleted before test
+ win_scheduled_task:
+ name: '{{test_scheduled_task_stat_name}}'
+ path: '{{test_scheduled_task_stat_path}}'
+ state: absent
+
+- name: create test user for service execution
+ ansible.windows.win_user:
+ name: '{{test_scheduled_task_stat_username}}'
+ password: '{{test_scheduled_task_stat_password}}'
+ state: present
+ groups_action: add
+ groups:
+ - Users
+ register: user_info
+
+# Run actual tests
+- block:
+ - name: normalise test account name
+ ansible.windows.win_powershell:
+ parameters:
+ SID: '{{ user_info.sid }}'
+ script: |
+ [CmdletBinding()]
+ param ([String]$SID)
+
+ $Ansible.Changed = $false
+ ([System.Security.Principal.SecurityIdentifier]$SID).Translate([System.Security.Principal.NTAccount]).Value
+ register: test_normalised_username
+
+ - set_fact:
+ test_normalised_username: '{{ test_normalised_username.output[0] }}'
+
+ - include_tasks: tests.yml
+
+ always:
+ - name: remove test user
+ ansible.windows.win_user:
+ name: '{{test_scheduled_task_stat_username}}'
+ state: absent
+
+ - name: delete task after test
+ win_scheduled_task:
+ name: '{{test_scheduled_task_stat_name}}'
+ path: '{{test_scheduled_task_stat_path}}'
+ state: absent
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task_stat/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task_stat/tasks/tests.yml
new file mode 100644
index 000000000..b0c8454d1
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task_stat/tasks/tests.yml
@@ -0,0 +1,175 @@
+---
+# folder stat tests
+
+# check_mode operation test
+- name: check_mode - get stat of a folder that is missing
+ win_scheduled_task_stat:
+ path: '{{test_scheduled_task_stat_path}}'
+ register: stat_folder_missing
+ check_mode: True
+
+- name: assert that check_mode works
+ assert:
+ that: stat_folder_missing is not skipped
+
+- name: get stat of a folder that is missing
+ win_scheduled_task_stat:
+ path: '{{test_scheduled_task_stat_path}}'
+ register: stat_folder_missing
+
+- name: assert get stat of a folder that is missing
+ assert:
+ that:
+ - stat_folder_missing.folder_exists == False
+
+- name: get stat of existing folder
+ win_scheduled_task_stat:
+ path: \
+ register: stat_folder_present
+
+- name: assert get stat of existing folder
+ assert:
+ that:
+ - stat_folder_present.folder_exists == True
+ - stat_folder_present.folder_task_count is defined
+ - stat_folder_present.folder_task_names is defined
+
+- name: create scheduled task in folder
+ win_scheduled_task:
+ path: '{{test_scheduled_task_stat_path}}'
+ name: '{{test_scheduled_task_stat_name}}'
+ state: present
+ logon_type: interactive_token
+ username: '{{ test_normalised_username }}'
+ author: Ansible Author
+ description: Fake description
+ execution_time_limit: PT23H
+ disallow_start_if_on_batteries: false
+ restart_count: 3
+ restart_interval: PT15M
+ actions:
+ - path: cmd.exe
+ - path: C:\temp\some.exe
+ arguments: --help
+ working_directory: C:\temp
+ triggers:
+ - type: boot
+ delay: PT15M
+ - type: monthly
+ days_of_month: 5,15,30
+ months_of_year: june,december
+ run_on_last_day_of_month: true
+ start_boundary: '2017-09-20T03:44:38'
+ - type: session_state_change
+ state_change: console_disconnect
+ user_id: '{{ test_normalised_username }}'
+
+- name: get stat of existing folder with task
+ win_scheduled_task_stat:
+ path: '{{test_scheduled_task_stat_path}}'
+ register: stat_folder_with_task
+
+- name: assert get stat of existing folder with task
+ assert:
+ that:
+ - stat_folder_with_task.folder_exists == True
+ - stat_folder_with_task.folder_task_count == 1
+ - stat_folder_with_task.folder_task_names[0] == "Test Task"
+ - stat_folder_with_task.task_exists is not defined
+
+# task stat tests
+- name: get stat of missing task with invalid folder
+ win_scheduled_task_stat:
+ path: fake path
+ name: fake task
+ register: stat_task_missing_folder
+
+- name: assert get stat of missing task with invalid folder
+ assert:
+ that:
+ - stat_task_missing_folder.folder_exists == False
+ - stat_task_missing_folder.task_exists == False
+
+- name: get stat of missing task
+ win_scheduled_task_stat:
+ path: '{{test_scheduled_task_stat_path}}'
+ name: fake task
+ register: stat_task_missing
+
+- name: assert get stat of missing task
+ assert:
+ that:
+ - stat_task_missing.task_exists == False
+
+- name: get stat of existing task
+ win_scheduled_task_stat:
+ path: '{{test_scheduled_task_stat_path}}'
+ name: '{{test_scheduled_task_stat_name}}'
+ register: stat_task_present
+
+- name: assert get stat of existing task
+ assert:
+ that:
+ - stat_task_present.task_exists == True
+ - stat_task_present.actions|count == 2
+ - stat_task_present.actions[0].path == "cmd.exe"
+ - stat_task_present.actions[0].type == "TASK_ACTION_EXEC"
+ - stat_task_present.actions[0].working_directory == None
+ - stat_task_present.actions[1].arguments == "--help"
+ - stat_task_present.actions[1].path == "C:\\temp\some.exe"
+ - stat_task_present.actions[1].type == "TASK_ACTION_EXEC"
+ - stat_task_present.actions[1].working_directory == "C:\\temp"
+ - stat_task_present.principal.display_name == None
+ - stat_task_present.principal.group_id == None
+ - stat_task_present.principal.logon_type == "TASK_LOGON_INTERACTIVE_TOKEN"
+ - stat_task_present.principal.run_level == "TASK_RUNLEVEL_LUA"
+ - stat_task_present.principal.user_id == test_normalised_username
+ - stat_task_present.registration_info.author == "Ansible Author"
+ - stat_task_present.registration_info.date is defined
+ - stat_task_present.registration_info.description == "Fake description"
+ - stat_task_present.settings.disallow_start_if_on_batteries == False
+ - stat_task_present.settings.execution_time_limit == "PT23H"
+ - stat_task_present.settings.restart_count == 3
+ - stat_task_present.settings.restart_interval == "PT15M"
+ - stat_task_present.state.status == "TASK_STATE_READY"
+ - stat_task_present.triggers|count == 3
+ - stat_task_present.triggers[0].delay == "PT15M"
+ - stat_task_present.triggers[0].type == "TASK_TRIGGER_BOOT"
+ - stat_task_present.triggers[0].repetition.stop_at_duration_end == False
+ - stat_task_present.triggers[0].repetition.duration == None
+ - stat_task_present.triggers[0].repetition.interval == None
+ - stat_task_present.triggers[1].days_of_month == "5,15,30"
+ - stat_task_present.triggers[1].months_of_year == "june,december"
+ - stat_task_present.triggers[1].run_on_last_day_of_month == True
+ - stat_task_present.triggers[1].start_boundary == "2017-09-20T03:44:38"
+ - stat_task_present.triggers[1].type == "TASK_TRIGGER_MONTHLY"
+ - stat_task_present.triggers[1].repetition.stop_at_duration_end == False
+ - stat_task_present.triggers[1].repetition.duration == None
+ - stat_task_present.triggers[1].repetition.interval == None
+ - stat_task_present.triggers[2].type == "TASK_TRIGGER_SESSION_STATE_CHANGE"
+ - stat_task_present.triggers[2].user_id == test_normalised_username
+ - stat_task_present.triggers[2].state_change == 2
+ - stat_task_present.triggers[2].state_change_str == "TASK_CONSOLE_DISCONNECT"
+
+- name: change principal to system account so it will run in the next step
+ win_scheduled_task:
+ name: '{{test_scheduled_task_stat_name}}'
+ path: '{{test_scheduled_task_stat_path}}'
+ username: SYSTEM
+
+- name: start the scheduled task
+ ansible.windows.win_command: schtasks.exe /Run /TN "{{test_scheduled_task_stat_path}}\{{test_scheduled_task_stat_name}}"
+
+- name: get stat of running task
+ win_scheduled_task_stat:
+ path: '{{test_scheduled_task_stat_path}}'
+ name: '{{test_scheduled_task_stat_name}}'
+ register: stat_task_running
+
+- name: assert stat of running task
+ assert:
+ that:
+ - stat_task_running.state.status == "TASK_STATE_RUNNING"
+
+- name: stop the scheduled task
+ ansible.windows.win_command: schtasks.exe /End /TN "{{test_scheduled_task_stat_path}}\{{test_scheduled_task_stat_name}}"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_scoop/aliases b/ansible_collections/community/windows/tests/integration/targets/win_scoop/aliases
new file mode 100644
index 000000000..e2eacc2b6
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_scoop/aliases
@@ -0,0 +1,3 @@
+shippable/windows/group3
+skip/windows/2012 # Need pwsh 5+
+skip/windows/2012-R2 # Need pwsh 5+
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_scoop/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_scoop/defaults/main.yml
new file mode 100644
index 000000000..10bf6204b
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_scoop/defaults/main.yml
@@ -0,0 +1,6 @@
+---
+test_scoop_package1: grep
+test_scoop_package2: sed
+test_scoop_packages:
+ - '{{ test_scoop_package1 }}'
+ - '{{ test_scoop_package2 }}'
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_scoop/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_scoop/tasks/main.yml
new file mode 100644
index 000000000..895cdffe2
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_scoop/tasks/main.yml
@@ -0,0 +1,8 @@
+---
+- name: ensure test packages are uninstalled
+ win_scoop:
+ name: '{{ test_scoop_packages }}'
+ state: absent
+
+- name: run tests
+ include_tasks: tests.yml
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_scoop/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_scoop/tasks/tests.yml
new file mode 100644
index 000000000..b773e61cb
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_scoop/tasks/tests.yml
@@ -0,0 +1,159 @@
+---
+- name: install package check mode
+ win_scoop:
+ name: '{{ test_scoop_package1 }}'
+ check_mode: yes
+ register: install_check
+
+- name: assert install package check mode
+ assert:
+ that:
+ - install_check is changed
+ - install_check.stdout is not defined
+
+- name: install package locally
+ win_scoop:
+ name: '{{ test_scoop_package1 }}'
+ register: install_locally
+
+- name: assert install package locally
+ assert:
+ that:
+ - install_locally is changed
+
+- name: install package locally (idempotent)
+ win_scoop:
+ name: '{{ test_scoop_package1 }}'
+ register: install_idempotent
+
+- name: assert install package locally (idempotent)
+ assert:
+ that:
+ - not install_idempotent is changed
+
+- name: install package globally
+ win_scoop:
+ name: '{{ test_scoop_package1 }}'
+ global: yes
+ register: install_globally
+
+- name: assert install package globally
+ assert:
+ that:
+ - install_globally is changed
+
+- name: install package globally
+ win_scoop:
+ name: '{{ test_scoop_package1 }}'
+ global: yes
+ register: install_globally_idempotent
+
+- name: assert install package globally (idempotent)
+ assert:
+ that:
+ - not install_globally_idempotent is changed
+
+- name: remove package
+ win_scoop:
+ name: '{{ test_scoop_package1 }}'
+ state: absent
+ register: remove
+
+- name: assert remove package
+ assert:
+ that:
+ - remove is changed
+
+- name: remove package (idempotent)
+ win_scoop:
+ name: '{{ test_scoop_package1 }}'
+ state: absent
+ register: remove_idempotent
+
+- name: assert remove package (idempotent)
+ assert:
+ that:
+ - not remove_idempotent is changed
+
+- name: remove package globally
+ win_scoop:
+ name: '{{ test_scoop_package1 }}'
+ state: absent
+ global: yes
+ register: remove_globally
+
+- name: assert remove package
+ assert:
+ that:
+ - remove_globally is changed
+
+- name: remove package globally (idempotent)
+ win_scoop:
+ name: '{{ test_scoop_package1 }}'
+ state: absent
+ global: yes
+ register: remove_globally_idempotent
+
+- name: assert remove package globally (idempotent)
+ assert:
+ that:
+ - not remove_globally_idempotent is changed
+
+- name: install package before check mode test
+ win_scoop:
+ name: '{{ test_scoop_package1 }}'
+
+- name: remove package check mode
+ win_scoop:
+ name: '{{ test_scoop_package1 }}'
+ state: absent
+ check_mode: yes
+ register: remove_check
+
+- name: assert remove package check mode
+ assert:
+ that:
+ - remove_check is changed
+ - remove_check.stdout is not defined
+
+- name: install multiple packages locally
+ win_scoop:
+ name: '{{ test_scoop_packages }}'
+ register: install_multiple
+
+- name: assert install multiple packages locally
+ assert:
+ that:
+ - install_multiple is changed
+
+- name: install multiple packages locally (idempotent)
+ win_scoop:
+ name: '{{ test_scoop_packages }}'
+ register: install_multiple_idempotent
+
+- name: assert install multiple packages locally (idempotent)
+ assert:
+ that:
+ - not install_multiple_idempotent is changed
+
+- name: remove multiple packages locally
+ win_scoop:
+ name: '{{ test_scoop_packages }}'
+ state: absent
+ register: remove_multiple
+
+- name: assert remove multiple packages
+ assert:
+ that:
+ - remove_multiple is changed
+
+- name: remove multiple packages locally (idempotent)
+ win_scoop:
+ name: '{{ test_scoop_packages }}'
+ state: absent
+ register: remove_multiple_idempotent
+
+- name: remove multiple packages locally (idempotent)
+ assert:
+ that:
+ - not remove_multiple_idempotent is changed
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_scoop_bucket/aliases b/ansible_collections/community/windows/tests/integration/targets/win_scoop_bucket/aliases
new file mode 100644
index 000000000..9a9d0737d
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_scoop_bucket/aliases
@@ -0,0 +1,3 @@
+shippable/windows/group2
+skip/windows/2012 # Need pwsh 5+
+skip/windows/2012-R2 # Need pwsh 5+
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_scoop_bucket/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_scoop_bucket/defaults/main.yml
new file mode 100644
index 000000000..c39f462e1
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_scoop_bucket/defaults/main.yml
@@ -0,0 +1,9 @@
+---
+test_scoop_bucket1:
+ name: extras
+test_scoop_bucket2:
+ name: versions
+ repo: https://github.com/ScoopInstaller/Versions
+test_scoop_buckets:
+ - '{{ test_scoop_bucket1 }}'
+ - '{{ test_scoop_bucket2 }}'
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_scoop_bucket/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_scoop_bucket/tasks/main.yml
new file mode 100644
index 000000000..fd7d4dac2
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_scoop_bucket/tasks/main.yml
@@ -0,0 +1,18 @@
+---
+- name: install git
+ win_scoop:
+ name: git
+
+- name: ensure test buckets are removed
+ win_scoop_bucket:
+ name: '{{ item.name }}'
+ state: absent
+ with_items: '{{ test_scoop_buckets }}'
+
+- name: run tests
+ include_tasks: tests.yml
+
+- name: uninstall git
+ win_scoop:
+ name: git
+ state: absent
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_scoop_bucket/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_scoop_bucket/tasks/tests.yml
new file mode 100644
index 000000000..f98eb4677
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_scoop_bucket/tasks/tests.yml
@@ -0,0 +1,86 @@
+---
+- name: add known bucket
+ win_scoop_bucket:
+ name: '{{ test_scoop_bucket1.name }}'
+ register: add_known
+
+- name: assert add add known bucket
+ assert:
+ that:
+ - add_known is changed
+
+- name: add known bucket (idempotent)
+ win_scoop_bucket:
+ name: '{{ test_scoop_bucket1.name }}'
+ register: add_known_idempotent
+
+- name: assert add known bucket (idempotent)
+ assert:
+ that:
+ - not add_known_idempotent is changed
+
+- name: remove known bucket
+ win_scoop_bucket:
+ name: '{{ test_scoop_bucket1.name }}'
+ state: absent
+ register: remove_known
+
+- name: assert remove known bucket
+ assert:
+ that:
+ - remove_known is changed
+
+- name: remove known bucket (idempotent)
+ win_scoop_bucket:
+ name: '{{ test_scoop_bucket1.name }}'
+ state: absent
+ register: remove_known_idempotent
+
+- name: assert remove package
+ assert:
+ that:
+ - not remove_known_idempotent is changed
+
+- name: add custom bucket
+ win_scoop_bucket:
+ name: '{{ test_scoop_bucket2.name }}'
+ repo: '{{ test_scoop_bucket2.repo }}'
+ register: add_custom
+
+- name: assert add add custom bucket
+ assert:
+ that:
+ - add_custom is changed
+
+- name: add custom bucket (idempotent)
+ win_scoop_bucket:
+ name: '{{ test_scoop_bucket2.name }}'
+ repo: '{{ test_scoop_bucket2.repo }}'
+ register: add_custom_idempotent
+
+- name: assert add custom bucket (idempotent)
+ assert:
+ that:
+ - not add_custom_idempotent is changed
+
+- name: remove custom bucket
+ win_scoop_bucket:
+ name: '{{ test_scoop_bucket2.name }}'
+ state: absent
+ register: remove_custom
+
+- name: assert remove custom bucket
+ assert:
+ that:
+ - remove_custom is changed
+
+- name: remove custom bucket (idempotent)
+ win_scoop_bucket:
+ name: '{{ test_scoop_bucket2.name }}'
+ state: absent
+ register: remove_custom_idempotent
+
+- name: assert remove package
+ assert:
+ that:
+ - not remove_custom_idempotent is changed \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_security_policy/aliases b/ansible_collections/community/windows/tests/integration/targets/win_security_policy/aliases
new file mode 100644
index 000000000..4cd27b3cb
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_security_policy/aliases
@@ -0,0 +1 @@
+shippable/windows/group1
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_security_policy/library/test_win_security_policy.ps1 b/ansible_collections/community/windows/tests/integration/targets/win_security_policy/library/test_win_security_policy.ps1
new file mode 100644
index 000000000..caafbdddb
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_security_policy/library/test_win_security_policy.ps1
@@ -0,0 +1,55 @@
+#!powershell
+
+# WANT_JSON
+# POWERSHELL_COMMON
+
+# basic script to get the lsit of users in a particular right
+# this is quite complex to put as a simple script so this is
+# just a simple module
+
+$ErrorActionPreference = 'Stop'
+
+$params = Parse-Args $args -supports_check_mode $false
+$section = Get-AnsibleParam -obj $params -name "section" -type "str" -failifempty $true
+$key = Get-AnsibleParam -obj $params -name "key" -type "str" -failifempty $true
+
+$result = @{
+ changed = $false
+}
+
+Function ConvertFrom-Ini($file_path) {
+ $ini = @{}
+ switch -Regex -File $file_path {
+ "^\[(.+)\]" {
+ $section = $matches[1]
+ $ini.$section = @{}
+ }
+ "(.+?)\s*=(.*)" {
+ $name = $matches[1].Trim()
+ $value = $matches[2].Trim()
+ if ($value -match "^\d+$") {
+ $value = [int]$value
+ }
+ elseif ($value.StartsWith('"') -and $value.EndsWith('"')) {
+ $value = $value.Substring(1, $value.Length - 2)
+ }
+
+ $ini.$section.$name = $value
+ }
+ }
+
+ $ini
+}
+
+$secedit_ini_path = [IO.Path]::GetTempFileName()
+&SecEdit.exe /export /cfg $secedit_ini_path /quiet
+$secedit_ini = ConvertFrom-Ini -file_path $secedit_ini_path
+
+if ($secedit_ini.ContainsKey($section)) {
+ $result.value = $secedit_ini.$section.$key
+}
+else {
+ $result.value = $null
+}
+
+Exit-Json $result
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_security_policy/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_security_policy/tasks/main.yml
new file mode 100644
index 000000000..4ea4a0522
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_security_policy/tasks/main.yml
@@ -0,0 +1,71 @@
+---
+- name: get current entry for audit
+ test_win_security_policy:
+ section: Event Audit
+ key: AuditSystemEvents
+ register: before_value_audit
+
+- name: get current entry for guest
+ test_win_security_policy:
+ section: System Access
+ key: NewGuestName
+ register: before_value_guest
+
+- name: get current value for the LegalNoticeText
+ ansible.windows.win_reg_stat:
+ path: HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\System
+ name: LegalNoticeText
+ register: original_legal_notice
+
+- block:
+ - name: set AuditSystemEvents entry before tests
+ win_security_policy:
+ section: Event Audit
+ key: AuditSystemEvents
+ value: 0
+
+ - name: set NewGuestName entry before tests
+ win_security_policy:
+ section: System Access
+ key: NewGuestName
+ value: Guest
+
+ - name: set LegalNoticeText with non-ASCII chars
+ ansible.windows.win_regedit:
+ path: HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\System
+ name: LegalNoticeText
+ data: "Légal Noticé\r\nNewline"
+
+ - name: run tests
+ include_tasks: tests.yml
+
+ # https://github.com/ansible-collections/community.windows/issues/153
+ - name: get the value for the LegalNoticeText after running tests
+ ansible.windows.win_reg_stat:
+ path: HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\System
+ name: LegalNoticeText
+ register: legal_notice
+
+ - name: verify the non-ASCII chars weren't corrupted
+ assert:
+ that:
+ - legal_notice.value == "Légal Noticé\r\nNewline"
+
+ always:
+ - name: reset entries for AuditSystemEvents
+ win_security_policy:
+ section: Event Audit
+ key: AuditSystemEvents
+ value: "{{before_value_audit.value}}"
+
+ - name: reset entries for NewGuestName
+ win_security_policy:
+ section: System Access
+ key: NewGuestName
+ value: "{{before_value_guest.value}}"
+
+ - name: reset LegalNoticeText
+ ansible.windows.win_regedit:
+ path: HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\System
+ name: LegalNoticeText
+ data: '{{ original_legal_notice.value }}'
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_security_policy/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_security_policy/tasks/tests.yml
new file mode 100644
index 000000000..724b6010a
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_security_policy/tasks/tests.yml
@@ -0,0 +1,186 @@
+---
+- name: fail with invalid section name
+ win_security_policy:
+ section: This is not a valid section
+ key: KeyName
+ value: 0
+ register: fail_invalid_section
+ failed_when: fail_invalid_section.msg != "The section 'This is not a valid section' does not exist in SecEdit.exe output ini"
+
+- name: fail with invalid key name
+ win_security_policy:
+ section: System Access
+ key: InvalidKey
+ value: 0
+ register: fail_invalid_key
+ failed_when: fail_invalid_key.msg != "The key 'InvalidKey' in section 'System Access' is not a valid key, cannot set this value"
+
+- name: change existing key check
+ win_security_policy:
+ section: Event Audit
+ key: AuditSystemEvents
+ value: 1
+ register: change_existing_check
+ check_mode: yes
+
+- name: get actual change existing key check
+ test_win_security_policy:
+ section: Event Audit
+ key: AuditSystemEvents
+ register: change_existing_actual_check
+
+- name: assert change existing key check
+ assert:
+ that:
+ - change_existing_check is changed
+ - change_existing_actual_check.value == 0
+
+- name: change existing key
+ win_security_policy:
+ section: Event Audit
+ key: AuditSystemEvents
+ value: 1
+ register: change_existing
+
+- name: get actual change existing key
+ test_win_security_policy:
+ section: Event Audit
+ key: AuditSystemEvents
+ register: change_existing_actual
+
+- name: assert change existing key
+ assert:
+ that:
+ - change_existing is changed
+ - change_existing_actual.value == 1
+
+- name: change existing key again
+ win_security_policy:
+ section: Event Audit
+ key: AuditSystemEvents
+ value: 1
+ register: change_existing_again
+
+- name: assert change existing key again
+ assert:
+ that:
+ - change_existing_again is not changed
+ - change_existing_again.value == 1
+
+- name: change existing key with string type
+ win_security_policy:
+ section: Event Audit
+ key: AuditSystemEvents
+ value: "1"
+ register: change_existing_key_with_type
+
+- name: assert change existing key with string type
+ assert:
+ that:
+ - change_existing_key_with_type is not changed
+ - change_existing_key_with_type.value == "1"
+
+- name: change existing string key check
+ win_security_policy:
+ section: System Access
+ key: NewGuestName
+ value: New Guest
+ register: change_existing_string_check
+ check_mode: yes
+
+- name: get actual change existing string key check
+ test_win_security_policy:
+ section: System Access
+ key: NewGuestName
+ register: change_existing_string_actual_check
+
+- name: assert change existing string key check
+ assert:
+ that:
+ - change_existing_string_check is changed
+ - change_existing_string_actual_check.value == "Guest"
+
+- name: change existing string key
+ win_security_policy:
+ section: System Access
+ key: NewGuestName
+ value: New Guest
+ register: change_existing_string
+
+- name: get actual change existing string key
+ test_win_security_policy:
+ section: System Access
+ key: NewGuestName
+ register: change_existing_string_actual
+
+- name: assert change existing string key
+ assert:
+ that:
+ - change_existing_string is changed
+ - change_existing_string_actual.value == "New Guest"
+
+- name: change existing string key again
+ win_security_policy:
+ section: System Access
+ key: NewGuestName
+ value: New Guest
+ register: change_existing_string_again
+
+- name: assert change existing string key again
+ assert:
+ that:
+ - change_existing_string_again is not changed
+ - change_existing_string_again.value == "New Guest"
+
+- name: add policy setting
+ win_security_policy:
+ section: Privilege Rights
+ # following key is empty by default
+ key: SeCreateTokenPrivilege
+ # add Guests
+ value: '*S-1-5-32-546'
+
+- name: get actual policy setting
+ test_win_security_policy:
+ section: Privilege Rights
+ key: SeCreateTokenPrivilege
+ register: add_policy_setting_actual
+
+- name: assert add policy setting
+ assert:
+ that:
+ - add_policy_setting_actual.value == '*S-1-5-32-546'
+
+- name: remove policy setting
+ win_security_policy:
+ section: Privilege Rights
+ key: SeCreateTokenPrivilege
+ value: ''
+ diff: yes
+ register: remove_policy_setting
+
+- name: get actual policy setting
+ test_win_security_policy:
+ section: Privilege Rights
+ key: SeCreateTokenPrivilege
+ register: remove_policy_setting_actual
+
+- name: assert remove policy setting
+ assert:
+ that:
+ - remove_policy_setting is changed
+ - remove_policy_setting.diff.prepared == "[Privilege Rights]\n-SeCreateTokenPrivilege = *S-1-5-32-546\n+SeCreateTokenPrivilege = "
+ - remove_policy_setting_actual.value is none
+
+- name: remove policy setting again
+ win_security_policy:
+ section: Privilege Rights
+ key: SeCreateTokenPrivilege
+ value: ''
+ register: remove_policy_setting_again
+
+- name: assert remove policy setting again
+ assert:
+ that:
+ - remove_policy_setting_again is not changed
+ - remove_policy_setting_again.value == ''
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_shortcut/aliases b/ansible_collections/community/windows/tests/integration/targets/win_shortcut/aliases
new file mode 100644
index 000000000..4cd27b3cb
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_shortcut/aliases
@@ -0,0 +1 @@
+shippable/windows/group1
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_shortcut/tasks/clean.yml b/ansible_collections/community/windows/tests/integration/targets/win_shortcut/tasks/clean.yml
new file mode 100644
index 000000000..3a9c9051e
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_shortcut/tasks/clean.yml
@@ -0,0 +1,37 @@
+# Test code for the file module.
+# (c) 2017, Dag Wieers <dag@wieers.com>
+
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+- name: Clean up Ansible website link
+ ansible.windows.win_file:
+ path: '%UserProfile%\Desktop\Ansible website.url'
+ state: absent
+
+- name: Clean up Registry Editor shortcut
+ ansible.windows.win_file:
+ path: '%Public%\Desktop\Registry Editor.lnk'
+ state: absent
+
+- name: Clean up Shell path shortcut
+ ansible.windows.win_file:
+ path: '%Public%\bin.lnk'
+ state: absent
+
+- name: Clean up Executable shortcut
+ ansible.windows.win_file:
+ path: '%Public%\Desktop\cmd.lnk'
+ state: absent
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_shortcut/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_shortcut/tasks/main.yml
new file mode 100644
index 000000000..cf04ea3b5
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_shortcut/tasks/main.yml
@@ -0,0 +1,34 @@
+# Test code for the file module.
+# (c) 2017, Dag Wieers <dag@wieers.com>
+
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+- name: Clean slate
+ import_tasks: clean.yml
+
+- name: Test in normal mode
+ import_tasks: tests.yml
+ vars:
+ in_check_mode: no
+
+- name: Clean slate
+ import_tasks: clean.yml
+
+- name: Test in check-mode
+ import_tasks: tests.yml
+ vars:
+ in_check_mode: yes
+ check_mode: yes
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_shortcut/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_shortcut/tasks/tests.yml
new file mode 100644
index 000000000..79e145c06
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_shortcut/tasks/tests.yml
@@ -0,0 +1,367 @@
+# Test code for the file module.
+# (c) 2017, Dag Wieers <dag@wieers.com>
+
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+- name: get current user profile location
+ raw: $env:USERPROFILE
+ check_mode: no
+ register: profile_result
+
+- set_fact:
+ profile_dir: '{{ profile_result.stdout_lines[0] }}'
+
+- name: Add Ansible website link on the desktop
+ win_shortcut:
+ src: https://ansible.com/
+ dest: '%UserProfile%\Desktop\Ansible website.url'
+ state: present
+ register: ansible_website_link_add
+
+- name: Check there was a change
+ assert:
+ that:
+ - ansible_website_link_add.changed == true
+ - ansible_website_link_add.dest == profile_dir + '\Desktop\Ansible website.url'
+ - ansible_website_link_add.src == 'https://ansible.com/'
+
+- name: Add Ansible website link on the desktop again
+ win_shortcut:
+ src: https://ansible.com/
+ dest: '%UserProfile%\Desktop\Ansible website.url'
+ state: present
+ register: ansible_website_link_add_again
+
+- name: Check there was no change (normal mode)
+ assert:
+ that:
+ - ansible_website_link_add_again.changed == false
+ - ansible_website_link_add_again.dest == profile_dir + '\Desktop\Ansible website.url'
+ - ansible_website_link_add_again.src == 'https://ansible.com/'
+ when: not in_check_mode
+
+- name: Check there was a change (check-mode)
+ assert:
+ that:
+ - ansible_website_link_add_again.changed == true
+ - ansible_website_link_add_again.dest == profile_dir + '\Desktop\Ansible website.url'
+ - ansible_website_link_add_again.src == 'https://ansible.com/'
+ when: in_check_mode
+
+- name: Remove link
+ win_shortcut:
+ dest: '%UserProfile%\Desktop\Ansible website.url'
+ state: absent
+ register: ansible_website_link_remove
+
+- name: Check there was a change (normal mode)
+ assert:
+ that:
+ - ansible_website_link_remove.changed == true
+ - ansible_website_link_remove.dest == profile_dir + '\Desktop\Ansible website.url'
+ when: not in_check_mode
+
+- name: Check there was no change (check-mode)
+ assert:
+ that:
+ - ansible_website_link_remove.changed == false
+ - ansible_website_link_remove.dest == profile_dir + '\Desktop\Ansible website.url'
+ when: in_check_mode
+
+- name: Remove link again
+ win_shortcut:
+ dest: '%UserProfile%\Desktop\Ansible website.url'
+ state: absent
+ register: ansible_website_link_remove_again
+
+- name: Check there was no change
+ assert:
+ that:
+ - ansible_website_link_remove_again.changed == false
+ - ansible_website_link_remove_again.dest == profile_dir + '\Desktop\Ansible website.url'
+
+- name: Add a regedit shortcut on the desktop
+ win_shortcut:
+ description: "Registry Editor"
+ src: regedit.exe
+ dest: '%Public%\Desktop\Registry Editor.lnk'
+ state: present
+ register: regedit_shortcut_add
+
+- name: Check there was a change
+ assert:
+ that:
+ - regedit_shortcut_add.changed == true
+ - regedit_shortcut_add.description == 'Registry Editor'
+ - regedit_shortcut_add.dest == 'C:\\Users\\Public\\Desktop\\Registry Editor.lnk'
+ - regedit_shortcut_add.src == 'C:\\Windows\\regedit.exe'
+
+- name: Add a regedit shortcut on the desktop again
+ win_shortcut:
+ description: "Registry Editor"
+ src: regedit.exe
+ dest: '%Public%\Desktop\Registry Editor.lnk'
+ state: present
+ register: regedit_shortcut_add_again
+
+- name: Check there was no change (normal mode)
+ assert:
+ that:
+ - regedit_shortcut_add_again.changed == false
+ - regedit_shortcut_add_again.description == 'Registry Editor'
+ - regedit_shortcut_add_again.dest == 'C:\\Users\\Public\\Desktop\\Registry Editor.lnk'
+ - regedit_shortcut_add_again.src == 'C:\\Windows\\regedit.exe'
+ when: not in_check_mode
+
+- name: Check there was a change (check-mode)
+ assert:
+ that:
+ - regedit_shortcut_add_again.changed == true
+ - regedit_shortcut_add_again.description == 'Registry Editor'
+ - regedit_shortcut_add_again.dest == 'C:\\Users\\Public\\Desktop\\Registry Editor.lnk'
+ - regedit_shortcut_add_again.src == 'C:\\Windows\\regedit.exe'
+ when: in_check_mode
+
+- name: Update a regedit shortcut on the desktop
+ win_shortcut:
+ description: "Registry Editor"
+ src: C:\BogusPath\regedit.exe
+ dest: '%Public%\Desktop\Registry Editor.lnk'
+ state: present
+ register: regedit_shortcut_update
+
+- name: Check there was a change
+ assert:
+ that:
+ - regedit_shortcut_update.changed == true
+ - regedit_shortcut_update.description == 'Registry Editor'
+ - regedit_shortcut_update.dest == 'C:\\Users\\Public\\Desktop\\Registry Editor.lnk'
+ - regedit_shortcut_update.src == 'C:\\BogusPath\\regedit.exe'
+
+- name: Update a regedit shortcut on the desktop again
+ win_shortcut:
+ description: "Registry Editor"
+ src: C:\BogusPath\regedit.exe
+ dest: '%Public%\Desktop\Registry Editor.lnk'
+ state: present
+ register: regedit_shortcut_update_again
+
+- name: Check there was no change (normal mode)
+ assert:
+ that:
+ - regedit_shortcut_update_again.changed == false
+ - regedit_shortcut_update_again.description == 'Registry Editor'
+ - regedit_shortcut_update_again.dest == 'C:\\Users\\Public\\Desktop\\Registry Editor.lnk'
+ - regedit_shortcut_update_again.src == 'C:\\BogusPath\\regedit.exe'
+ when: not in_check_mode
+
+- name: Check there was a change (check-mode)
+ assert:
+ that:
+ - regedit_shortcut_update_again.changed == true
+ - regedit_shortcut_update_again.description == 'Registry Editor'
+ - regedit_shortcut_update_again.dest == 'C:\\Users\\Public\\Desktop\\Registry Editor.lnk'
+ - regedit_shortcut_update_again.src == 'C:\\BogusPath\\regedit.exe'
+ when: in_check_mode
+
+- name: Add an (explicit) icon
+ win_shortcut:
+ description: "Registry Editor"
+ src: C:\Windows\regedit.exe
+ dest: '%Public%\Desktop\Registry Editor.lnk'
+ icon: 'C:\Windows\regedit.exe,0'
+ state: present
+ register: regedit_shortcut_add_icon
+
+- name: Check there was a change
+ assert:
+ that:
+ - regedit_shortcut_add_icon.changed == true
+ - regedit_shortcut_add_icon.description == 'Registry Editor'
+ - regedit_shortcut_add_icon.dest == 'C:\\Users\\Public\\Desktop\\Registry Editor.lnk'
+ - regedit_shortcut_add_icon.icon == 'C:\\Windows\\regedit.exe,0'
+ - regedit_shortcut_add_icon.src == 'C:\\Windows\\regedit.exe'
+
+- name: Add an (explicit) icon again
+ win_shortcut:
+ description: "Registry Editor"
+ src: C:\Windows\regedit.exe
+ dest: '%Public%\Desktop\Registry Editor.lnk'
+ icon: 'C:\Windows\regedit.exe,0'
+ state: present
+ register: regedit_shortcut_add_icon_again
+
+- name: Check there was no change (normal mode)
+ assert:
+ that:
+ - regedit_shortcut_add_icon_again.changed == false
+ - regedit_shortcut_add_icon_again.description == 'Registry Editor'
+ - regedit_shortcut_add_icon_again.dest == 'C:\\Users\\Public\\Desktop\\Registry Editor.lnk'
+ - regedit_shortcut_add_icon_again.icon == 'C:\\Windows\\regedit.exe,0'
+ - regedit_shortcut_add_icon_again.src == 'C:\\Windows\\regedit.exe'
+ when: not in_check_mode
+
+- name: Check there was a change (check-mode)
+ assert:
+ that:
+ - regedit_shortcut_add_icon_again.changed == true
+ - regedit_shortcut_add_icon_again.description == 'Registry Editor'
+ - regedit_shortcut_add_icon_again.dest == 'C:\\Users\\Public\\Desktop\\Registry Editor.lnk'
+ - regedit_shortcut_add_icon_again.icon == 'C:\\Windows\\regedit.exe,0'
+ - regedit_shortcut_add_icon_again.src == 'C:\\Windows\\regedit.exe'
+ when: in_check_mode
+
+- name: Remove shortcut
+ win_shortcut:
+ dest: '%Public%\Desktop\Registry Editor.lnk'
+ state: absent
+ register: regedit_shortcut_remove
+
+- name: Check there was a change (normal mode)
+ assert:
+ that:
+ - regedit_shortcut_remove.changed == true
+ - regedit_shortcut_remove.dest == 'C:\\Users\\Public\\Desktop\\Registry Editor.lnk'
+ when: not in_check_mode
+
+- name: Check there was no change (check-mode)
+ assert:
+ that:
+ - regedit_shortcut_remove.changed == false
+ - regedit_shortcut_remove.dest == 'C:\\Users\\Public\\Desktop\\Registry Editor.lnk'
+ when: in_check_mode
+
+- name: Remove shortcut again
+ win_shortcut:
+ dest: '%Public%\Desktop\Registry Editor.lnk'
+ state: absent
+ register: regedit_shortcut_remove_again
+
+- name: Check there was no change
+ assert:
+ that:
+ - regedit_shortcut_remove_again.changed == false
+ - regedit_shortcut_remove_again.dest == 'C:\\Users\\Public\\Desktop\\Registry Editor.lnk'
+
+- name: Create shortcut to shell path
+ win_shortcut:
+ dest: '%Public%\bin.lnk'
+ src: shell:RecycleBinFolder
+ state: present
+ register: shell_add
+
+- name: Check there was a change
+ assert:
+ that:
+ - shell_add is changed
+ - shell_add.dest == 'C:\\Users\\Public\\bin.lnk'
+ - shell_add.src == 'shell:RecycleBinFolder'
+
+- name: Create shortcut to shell path again
+ win_shortcut:
+ dest: '%Public%\bin.lnk'
+ src: shell:RecycleBinFolder
+ state: present
+ register: shell_add_again
+
+- name: Check there was no change (normal mode)
+ assert:
+ that:
+ - not shell_add_again is changed
+ - shell_add_again.src == 'shell:RecycleBinFolder'
+ when: not in_check_mode
+
+- name: Check there was a change (check-mode)
+ assert:
+ that:
+ - shell_add_again is changed
+ when: in_check_mode
+
+- name: Change shortcut to another shell path
+ win_shortcut:
+ dest: '%Public%\bin.lnk'
+ src: shell:Start Menu
+ state: present
+ register: shell_change
+
+- name: Check there was a change
+ assert:
+ that:
+ - shell_change is changed
+ - shell_change.src == 'shell:Start Menu'
+
+- name: Create shortcut to an executable without run as admin
+ win_shortcut:
+ dest: '%Public%\Desktop\cmd.lnk'
+ src: '%SystemRoot%\System32\cmd.exe'
+ state: present
+ register: shell_exe_limited
+
+- name: Get run as admin flag state
+ ansible.windows.win_shell: |
+ $shortcut = "$env:Public\Desktop\cmd.lnk"
+ $flags = [System.BitConverter]::ToUInt32([System.IO.FIle]::ReadAllBytes($shortcut), 20)
+ ($flags -band 0x00002000) -eq 0x00002000
+ register: shell_exe_limited_actual
+
+- name: Check that run as admin flag wasn't set (normal mode)
+ assert:
+ that:
+ - shell_exe_limited is changed
+ - not shell_exe_limited_actual.stdout_lines[0]|bool
+ when: not in_check_mode
+
+- name: Check that exe shortcut results in a change (check-mode)
+ assert:
+ that:
+ - shell_exe_limited is changed
+ when: in_check_mode
+
+- name: Set shortcut to run as admin
+ win_shortcut:
+ dest: '%Public%\Desktop\cmd.lnk'
+ src: '%SystemRoot%\System32\cmd.exe'
+ run_as_admin: True
+ state: present
+ register: shell_exe_admin
+
+- name: Get run as admin flag state
+ ansible.windows.win_shell: |
+ $shortcut = "$env:Public\Desktop\cmd.lnk"
+ $flags = [System.BitConverter]::ToUInt32([System.IO.FIle]::ReadAllBytes($shortcut), 20)
+ ($flags -band 0x00002000) -eq 0x00002000
+ register: shell_exe_admin_actual
+
+- name: Check that run as admin flag was set (normal mode)
+ assert:
+ that:
+ - shell_exe_admin is changed
+ - shell_exe_admin_actual.stdout_lines[0]|bool
+ when: not in_check_mode
+
+- name: Set shortcut to run as admin again
+ win_shortcut:
+ dest: '%Public%\Desktop\cmd.lnk'
+ src: '%SystemRoot%\System32\cmd.exe'
+ run_as_admin: True
+ state: present
+ register: shell_exe_admin_again
+
+- name: Check that set run as admin wasn't changed (normal mode)
+ assert:
+ that:
+ - not shell_exe_admin_again is changed
+ when: not in_check_mode
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_snmp/aliases b/ansible_collections/community/windows/tests/integration/targets/win_snmp/aliases
new file mode 100644
index 000000000..3cf5b97e8
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_snmp/aliases
@@ -0,0 +1 @@
+shippable/windows/group3
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_snmp/tasks/cleanup.yml b/ansible_collections/community/windows/tests/integration/targets/win_snmp/tasks/cleanup.yml
new file mode 100644
index 000000000..ef446cb73
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_snmp/tasks/cleanup.yml
@@ -0,0 +1,16 @@
+---
+ - name: Make sure there are no existing SNMP configuration settings
+ ansible.windows.win_regedit:
+ path: "{{ item }}"
+ state: absent
+ loop:
+ - "{{ permitted_managers_key }}"
+ - "{{ valid_communities_key }}"
+
+ - name: Create skeleton registry keys for SNMP
+ ansible.windows.win_regedit:
+ path: "{{ item }}"
+ state: present
+ loop:
+ - "{{ permitted_managers_key }}"
+ - "{{ valid_communities_key }}"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_snmp/tasks/cleanup_using_module.yml b/ansible_collections/community/windows/tests/integration/targets/win_snmp/tasks/cleanup_using_module.yml
new file mode 100644
index 000000000..472a03e7e
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_snmp/tasks/cleanup_using_module.yml
@@ -0,0 +1,26 @@
+---
+ - name: Set no SNMP community or SNMP manager
+ register: snmp_cleanup
+ win_snmp:
+ action: set
+ community_strings: []
+ permitted_managers: []
+
+ - name: Check registry for no SNMP community
+ register: snmp_cleanup_reg_community
+ ansible.windows.win_reg_stat:
+ path: "{{ valid_communities_key }}"
+ name: snmp-cleanup
+
+ - name: Check registry for no SNMP manager
+ register: snmp_cleanup_reg_manager
+ ansible.windows.win_reg_stat:
+ path: "{{ permitted_managers_key }}"
+ name: 1
+
+ - name: Asset SNMP set operation results in no remaining SNMP details
+ assert:
+ that:
+ - snmp_cleanup.changed
+ - snmp_cleanup_reg_community.exists == false
+ - snmp_cleanup_reg_manager.exists == false
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_snmp/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_snmp/tasks/main.yml
new file mode 100644
index 000000000..09000d6e9
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_snmp/tasks/main.yml
@@ -0,0 +1,8 @@
+---
+ - include_tasks: cleanup.yml
+ - include_tasks: snmp_community.yml
+ - include_tasks: cleanup.yml
+ - include_tasks: snmp_managers.yml
+ - include_tasks: output_only.yml
+ - include_tasks: cleanup_using_module.yml
+ - include_tasks: cleanup.yml
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_snmp/tasks/output_only.yml b/ansible_collections/community/windows/tests/integration/targets/win_snmp/tasks/output_only.yml
new file mode 100644
index 000000000..7115da45d
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_snmp/tasks/output_only.yml
@@ -0,0 +1,24 @@
+---
+ # Already tested
+ - name: Add an SNMP manager and an SNMP community
+ win_snmp:
+ action: add
+ community_strings:
+ - snmp-cleanup
+ permitted_managers:
+ - 192.168.1.1
+
+ - name: Run without options
+ register: snmp_no_options
+ win_snmp:
+
+ - name: Assert no changes occurred when no options provided
+ assert:
+ that:
+ - not snmp_no_options.changed
+
+ - name: Assert community strings and permitted managers are correctly returned
+ assert:
+ that:
+ - "'snmp-cleanup' in snmp_no_options.community_strings"
+ - "'192.168.1.1' in snmp_no_options.permitted_managers"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_snmp/tasks/snmp_community.yml b/ansible_collections/community/windows/tests/integration/targets/win_snmp/tasks/snmp_community.yml
new file mode 100644
index 000000000..d206d179c
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_snmp/tasks/snmp_community.yml
@@ -0,0 +1,165 @@
+---
+ - name: Add initial SNMP community
+ register: snmp_community
+ win_snmp:
+ action: add
+ community_strings:
+ - ansible-ro-test
+
+ - name: Check initial SNMP community exists in registry
+ register: snmp_community_reg
+ ansible.windows.win_reg_stat:
+ path: "{{ valid_communities_key }}"
+ name: ansible-ro-test
+
+ - name: Assert initial SNMP community is correct
+ assert:
+ that:
+ - snmp_community is changed
+ - snmp_community_reg.exists
+ - snmp_community_reg.type == 'REG_DWORD'
+ - snmp_community_reg.value == 4
+
+ - name: Add initial SNMP community again
+ register: snmp_community_again
+ win_snmp:
+ action: add
+ community_strings:
+ - ansible-ro-test
+
+ - name: Check no change occurred when adding SNMP community again
+ assert:
+ that:
+ - snmp_community_again is not changed
+
+ - name: Add next SNMP community
+ register: snmp_community_next
+ win_snmp:
+ action: add
+ community_strings:
+ - ansible-ro-test-next
+
+ - name: Check initial SNMP community still exists in registry
+ register: snmp_community_reg_orig
+ ansible.windows.win_reg_stat:
+ path: "{{ valid_communities_key }}"
+ name: ansible-ro-test
+
+ - name: Check next SNMP community exists in registry
+ register: snmp_community_reg_next
+ ansible.windows.win_reg_stat:
+ path: "{{ valid_communities_key }}"
+ name: ansible-ro-test-next
+
+ - name: Assert initial SNMP community still exists
+ assert:
+ that:
+ - snmp_community_reg_orig.exists
+ - snmp_community_reg_orig.type == 'REG_DWORD'
+ - snmp_community_reg_orig.value == 4
+
+ - name: Assert next SNMP community exists
+ assert:
+ that:
+ - snmp_community_next is changed
+ - snmp_community_reg_next.exists
+ - snmp_community_reg_next.type == 'REG_DWORD'
+ - snmp_community_reg_next.value == 4
+
+ - name: Replace SNMP community
+ register: snmp_community_replace
+ win_snmp:
+ action: set
+ community_strings:
+ - ansible-ro-test-replace
+
+ - name: Check initial SNMP community does not exist in registry
+ register: snmp_community_reg_orig_replace
+ ansible.windows.win_reg_stat:
+ path: "{{ valid_communities_key }}"
+ name: ansible-ro-test
+
+ - name: Check next SNMP community does not exist in registry
+ register: snmp_community_reg_next_replace
+ ansible.windows.win_reg_stat:
+ path: "{{ valid_communities_key }}"
+ name: ansible-ro-test-next
+
+ - name: Check replace SNMP community exists in registry
+ register: snmp_community_reg_replace
+ ansible.windows.win_reg_stat:
+ path: "{{ valid_communities_key }}"
+ name: ansible-ro-test-replace
+
+ - name: Assert replace SNMP community exists and others are replaced
+ assert:
+ that:
+ - snmp_community_replace is changed
+ - snmp_community_reg_orig_replace.exists == false
+ - snmp_community_reg_next_replace.exists == false
+ - snmp_community_reg_replace.exists
+ - snmp_community_reg_replace.type == 'REG_DWORD'
+ - snmp_community_reg_replace.value == 4
+
+ # This task has already been tested
+ - name: Add another SNMP community before testing removal
+ win_snmp:
+ action: add
+ community_strings:
+ - ansible-ro-remove-add
+
+ - name: Remove the replaced SNMP community
+ register: snmp_community_remove
+ win_snmp:
+ action: remove
+ community_strings:
+ - ansible-ro-test-replace
+
+ - name: Check replace SNMP community is removed in registry
+ register: snmp_community_reg_remove
+ ansible.windows.win_reg_stat:
+ path: "{{ valid_communities_key }}"
+ name: ansible-ro-test-replace
+
+ - name: Check SNMP community that was added for testing removal exists in registry
+ register: snmp_community_reg_remove_add
+ ansible.windows.win_reg_stat:
+ path: "{{ valid_communities_key }}"
+ name: ansible-ro-remove-add
+
+ - name: Assert removal of SNMP community succeeded and next SNMP community remains
+ assert:
+ that:
+ - snmp_community_remove is changed
+ - snmp_community_reg_remove.exists == false
+ - snmp_community_reg_remove_add.exists
+ - snmp_community_reg_remove_add.type == 'REG_DWORD'
+ - snmp_community_reg_remove_add.value == 4
+
+ - name: Remove the replaced SNMP community (again)
+ register: snmp_community_remove
+ win_snmp:
+ action: remove
+ community_strings:
+ - ansible-ro-test-replace
+
+ - name: Check replace SNMP community is removed in registry (again)
+ register: snmp_community_reg_remove
+ ansible.windows.win_reg_stat:
+ path: "{{ valid_communities_key }}"
+ name: ansible-ro-test-replace
+
+ - name: Check SNMP community that was added for testing removal exists in registry (again)
+ register: snmp_community_reg_remove_add
+ ansible.windows.win_reg_stat:
+ path: "{{ valid_communities_key }}"
+ name: ansible-ro-remove-add
+
+ - name: Assert removal of SNMP community succeeded and next SNMP community remains (again)
+ assert:
+ that:
+ - snmp_community_remove is not changed
+ - snmp_community_reg_remove.exists == false
+ - snmp_community_reg_remove_add.exists
+ - snmp_community_reg_remove_add.type == 'REG_DWORD'
+ - snmp_community_reg_remove_add.value == 4
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_snmp/tasks/snmp_managers.yml b/ansible_collections/community/windows/tests/integration/targets/win_snmp/tasks/snmp_managers.yml
new file mode 100644
index 000000000..227281d81
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_snmp/tasks/snmp_managers.yml
@@ -0,0 +1,158 @@
+---
+ - name: Add initial SNMP manager
+ register: snmp_manager
+ win_snmp:
+ action: add
+ permitted_managers:
+ - 192.168.1.1
+
+ - name: Check initial SNMP manager exists in registry
+ register: snmp_manager_reg
+ ansible.windows.win_reg_stat:
+ path: "{{ permitted_managers_key }}"
+ name: 1
+
+ - name: Assert initial SNMP manager is correct
+ assert:
+ that:
+ - snmp_manager is changed
+ - snmp_manager_reg.exists
+ - snmp_manager_reg.type == 'REG_SZ'
+ - snmp_manager_reg.value == '192.168.1.1'
+
+ - name: Add initial SNMP manager again
+ register: snmp_manager_again
+ win_snmp:
+ action: add
+ permitted_managers:
+ - 192.168.1.1
+
+ - name: Check no change occurred when adding SNMP manager again
+ assert:
+ that:
+ - snmp_manager_again is not changed
+
+ - name: Add next SNMP manager
+ register: snmp_manager_next
+ win_snmp:
+ action: add
+ permitted_managers:
+ - 192.168.1.2
+
+ - name: Check initial SNMP manager still exists in registry
+ register: snmp_manager_reg_orig
+ ansible.windows.win_reg_stat:
+ path: "{{ permitted_managers_key }}"
+ name: 1
+
+ - name: Check next SNMP manager exists in registry
+ register: snmp_manager_reg_next
+ ansible.windows.win_reg_stat:
+ path: "{{ permitted_managers_key }}"
+ name: 2
+
+ - name: Assert initial SNMP manager still exists
+ assert:
+ that:
+ - snmp_manager_reg_orig.exists
+ - snmp_manager_reg_orig.type == 'REG_SZ'
+ - snmp_manager_reg_orig.value == '192.168.1.1'
+
+ - name: Assert next SNMP manager exists
+ assert:
+ that:
+ - snmp_manager_next is changed
+ - snmp_manager_reg_next.exists
+ - snmp_manager_reg_next.type == 'REG_SZ'
+ - snmp_manager_reg_next.value == '192.168.1.2'
+
+ - name: Replace SNMP manager
+ register: snmp_manager_replace
+ win_snmp:
+ action: set
+ permitted_managers:
+ - 192.168.1.10
+
+ - name: Check next SNMP manager does not exist in registry
+ register: snmp_manager_reg_next_replace
+ ansible.windows.win_reg_stat:
+ path: "{{ permitted_managers_key }}"
+ name: 2
+
+ - name: Check replace SNMP manager exists in registry (overrides original slot)
+ register: snmp_manager_reg_replace
+ ansible.windows.win_reg_stat:
+ path: "{{ permitted_managers_key }}"
+ name: 1
+
+ - name: Assert replace SNMP manager exists and others are replaced
+ assert:
+ that:
+ - snmp_manager_replace is changed
+ - snmp_manager_reg_next_replace.exists == false
+ - snmp_manager_reg_replace.exists
+ - snmp_manager_reg_replace.type == 'REG_SZ'
+ - snmp_manager_reg_replace.value == '192.168.1.10'
+
+ # This task has already been tested
+ - name: Add another SNMP manager before testing removal
+ win_snmp:
+ action: add
+ permitted_managers:
+ - 192.168.1.20
+
+ - name: Remove the replaced SNMP manager
+ register: snmp_manager_remove
+ win_snmp:
+ action: remove
+ permitted_managers:
+ - 192.168.1.10
+
+ - name: Check replace SNMP manager is removed in registry
+ register: snmp_manager_reg_remove
+ ansible.windows.win_reg_stat:
+ path: "{{ permitted_managers_key }}"
+ name: 1
+
+ - name: Check SNMP manager that was added for testing removal exists in registry
+ register: snmp_manager_reg_remove_add
+ ansible.windows.win_reg_stat:
+ path: "{{ permitted_managers_key }}"
+ name: 2
+
+ - name: Assert removal of SNMP manager succeeded and next SNMP manager remains
+ assert:
+ that:
+ - snmp_manager_remove is changed
+ - snmp_manager_reg_remove.exists == false
+ - snmp_manager_reg_remove_add.exists
+ - snmp_manager_reg_remove_add.type == 'REG_SZ'
+ - snmp_manager_reg_remove_add.value == '192.168.1.20'
+
+ - name: Remove the replaced SNMP manager (again)
+ register: snmp_manager_remove
+ win_snmp:
+ action: remove
+ permitted_managers:
+ - 192.168.1.10
+
+ - name: Check replace SNMP manager is removed in registry (again)
+ register: snmp_manager_reg_remove
+ ansible.windows.win_reg_stat:
+ path: "{{ permitted_managers_key }}"
+ name: 1
+
+ - name: Check SNMP manager that was added for testing removal exists in registry (again)
+ register: snmp_manager_reg_remove_add
+ ansible.windows.win_reg_stat:
+ path: "{{ permitted_managers_key }}"
+ name: 2
+
+ - name: Assert removal of SNMP manager succeeded and next SNMP manager remains (again)
+ assert:
+ that:
+ - snmp_manager_remove is not changed
+ - snmp_manager_reg_remove.exists == false
+ - snmp_manager_reg_remove_add.exists
+ - snmp_manager_reg_remove_add.type == 'REG_SZ'
+ - snmp_manager_reg_remove_add.value == '192.168.1.20'
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_snmp/vars/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_snmp/vars/main.yml
new file mode 100644
index 000000000..610be839f
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_snmp/vars/main.yml
@@ -0,0 +1,3 @@
+---
+ permitted_managers_key: 'HKLM:\System\CurrentControlSet\services\SNMP\Parameters\PermittedManagers'
+ valid_communities_key: 'HKLM:\System\CurrentControlSet\services\SNMP\Parameters\ValidCommunities'
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_timezone/aliases b/ansible_collections/community/windows/tests/integration/targets/win_timezone/aliases
new file mode 100644
index 000000000..215e0b069
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_timezone/aliases
@@ -0,0 +1 @@
+shippable/windows/group4
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_timezone/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_timezone/tasks/main.yml
new file mode 100644
index 000000000..63f449e46
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_timezone/tasks/main.yml
@@ -0,0 +1,19 @@
+- name: Determine if server has tzutil.exe installed
+ ansible.windows.win_command: tzutil.exe /l
+ register: tzutil
+ ignore_errors: yes
+
+- name: Only run tests if tzutil.exe is installed
+ when: tzutil.rc == 0
+ block:
+
+ - name: Test in normal mode
+ import_tasks: tests.yml
+ vars:
+ in_check_mode: no
+
+ - name: Test in check-mode
+ import_tasks: tests.yml
+ vars:
+ in_check_mode: yes
+ check_mode: yes
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_timezone/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_timezone/tasks/tests.yml
new file mode 100644
index 000000000..e03f4f1e1
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_timezone/tasks/tests.yml
@@ -0,0 +1,100 @@
+# NOTE: Set to a known starting value, store original
+- name: Change starting timezone to GMT
+ win_timezone:
+ timezone: GMT Standard Time
+ register: original
+
+# NOTE: We don't know if it changed, we don't care
+- name: Test GMT timezone
+ assert:
+ that:
+ - original.timezone == 'GMT Standard Time'
+
+- name: Change timezone to GMT+1
+ win_timezone:
+ timezone: Romance Standard Time
+ register: romance
+
+- name: Test GMT+1 timezone
+ assert:
+ that:
+ - romance is changed
+ - romance.previous_timezone == 'GMT Standard Time'
+ - romance.timezone == 'Romance Standard Time'
+ when: not in_check_mode
+
+- name: Test GMT+1 timezone
+ assert:
+ that:
+ - romance is changed
+ - romance.previous_timezone == original.timezone
+ - romance.timezone == 'Romance Standard Time'
+ when: in_check_mode
+
+- name: Change timezone to GMT+1 again
+ win_timezone:
+ timezone: Romance Standard Time
+ register: romance
+
+- name: Test GMT+1 timezone
+ assert:
+ that:
+ - romance is not changed
+ - romance.previous_timezone == 'Romance Standard Time'
+ - romance.timezone == 'Romance Standard Time'
+ when: not in_check_mode
+
+- name: Test GMT+1 timezone
+ assert:
+ that:
+ - romance is changed
+ - romance.previous_timezone == original.timezone
+ - romance.timezone == 'Romance Standard Time'
+ when: in_check_mode
+
+- name: Change timezone to GMT+6
+ win_timezone:
+ timezone: Central Standard Time
+ register: central
+
+- name: Test GMT-6 timezone
+ assert:
+ that:
+ - central is changed
+ - central.previous_timezone == 'Romance Standard Time'
+ - central.timezone == 'Central Standard Time'
+ when: not in_check_mode
+
+- name: Test GMT+1 timezone
+ assert:
+ that:
+ - central is changed
+ - central.previous_timezone == original.timezone
+ - central.timezone == 'Central Standard Time'
+ when: in_check_mode
+
+- name: Change timezone to dstoff
+ win_timezone:
+ timezone: Eastern Standard Time_dstoff
+ register: dstoff_result
+
+- name: Test dstoff timezone
+ assert:
+ that:
+ - dstoff_result is changed
+ - dstoff_result.timezone == 'Eastern Standard Time_dstoff'
+
+- name: Change timezone to GMT+666
+ win_timezone:
+ timezone: Dag's Standard Time
+ register: dag
+ ignore_errors: yes
+
+- name: Test GMT+666 timezone
+ assert:
+ that:
+ - dag is failed
+
+- name: Restore original timezone
+ win_timezone:
+ timezone: '{{ original.timezone }}' \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_toast/aliases b/ansible_collections/community/windows/tests/integration/targets/win_toast/aliases
new file mode 100644
index 000000000..ebd7be746
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_toast/aliases
@@ -0,0 +1,2 @@
+shippable/windows/group1
+disabled
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_toast/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_toast/tasks/main.yml
new file mode 100644
index 000000000..735d55b1a
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_toast/tasks/main.yml
@@ -0,0 +1,13 @@
+- name: Set up tests
+ import_tasks: setup.yml
+
+- name: Test in normal mode
+ import_tasks: tests.yml
+ vars:
+ in_check_mode: no
+
+- name: Test in check mode
+ import_tasks: tests.yml
+ vars:
+ in_check_mode: yes
+ check_mode: yes
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_toast/tasks/setup.yml b/ansible_collections/community/windows/tests/integration/targets/win_toast/tasks/setup.yml
new file mode 100644
index 000000000..869bc5f51
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_toast/tasks/setup.yml
@@ -0,0 +1,27 @@
+- name: Get OS version
+ ansible.windows.win_shell: '[Environment]::OSVersion.Version.Major'
+ register: os_version
+
+- name: Get logged in user count (using explorer exe as a proxy)
+ ansible.windows.win_shell: (get-process -name explorer -EA silentlyContinue).Count
+ register: user_count
+
+- name: debug os_version
+ debug:
+ var: os_version
+ verbosity: 2
+
+- name: debug user_count
+ debug:
+ var: user_count
+ verbosity: 2
+
+- name: Set fact if toast cannot be made
+ set_fact:
+ can_toast: False
+ when: os_version.stdout|int < 10
+
+- name: Set fact if toast can be made
+ set_fact:
+ can_toast: True
+ when: os_version.stdout|int >= 10
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_toast/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_toast/tasks/tests.yml
new file mode 100644
index 000000000..d1d4ece10
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_toast/tasks/tests.yml
@@ -0,0 +1,106 @@
+- name: Warn user
+ win_toast:
+ expire: 10
+ msg: Keep calm and carry on.
+ register: msg_result
+ ignore_errors: True
+
+- name: Test msg_result when can_toast is true (normal mode, users)
+ assert:
+ that:
+ - msg_result is not failed
+ - msg_result.time_taken > 10
+ when:
+ - can_toast == True
+ - in_check_mode == False
+ - user_count.stdout|int > 0
+
+- name: Test msg_result when can_toast is true (normal mode, no users)
+ assert:
+ that:
+ - msg_result is not failed
+ - msg_result.time_taken > 0.1
+ - msg_result.toast_sent == False
+ when:
+ - can_toast == True
+ - in_check_mode == False
+ - user_count.stdout|int == 0
+
+- name: Test msg_result when can_toast is true (check mode, users)
+ assert:
+ that:
+ - msg_result is not failed
+ - msg_result.time_taken > 0.1
+ when:
+ - can_toast == True
+ - in_check_mode == True
+
+- name: Test msg_result when can_toast is true (check mode, no users)
+ assert:
+ that:
+ - msg_result is not failed
+ - msg_result.time_taken > 0.1
+ - msg_result.toast_sent == False
+ when:
+ - can_toast == True
+ - in_check_mode == True
+ - user_count.stdout|int == 0
+
+- name: Test msg_result when can_toast is false
+ assert:
+ that:
+ - msg_result is failed
+ when: can_toast == False
+
+- name: Warn user again
+ win_toast:
+ expire: 10
+ msg: Keep calm and carry on.
+ register: msg_result2
+ ignore_errors: True
+
+- name: Test msg_result2 when can_toast is true (normal mode, users)
+ assert:
+ that:
+ - msg_result2 is not failed
+ - msg_result2.time_taken > 10
+ when:
+ - can_toast == True
+ - in_check_mode == False
+ - user_count.stdout|int > 0
+
+- name: Test msg_result2 when can_toast is true (normal mode, no users)
+ assert:
+ that:
+ - msg_result2 is not failed
+ - msg_result2.time_taken > 0.1
+ when:
+ - can_toast == True
+ - in_check_mode == False
+ - user_count.stdout|int == 0
+
+- name: Test msg_result2 when can_toast is true (check mode, users)
+ assert:
+ that:
+ - msg_result2 is not failed
+ - msg_result2.time_taken > 0.1
+ when:
+ - can_toast == True
+ - in_check_mode == False
+ - user_count.stdout|int > 0
+
+- name: Test msg_result2 when can_toast is true (check mode, no users)
+ assert:
+ that:
+ - msg_result2 is not failed
+ - msg_result2.time_taken > 0.1
+ when:
+ - can_toast == True
+ - in_check_mode == False
+ - user_count.stdout|int == 0
+
+- name: Test msg_result2 when can_toast is false
+ assert:
+ that:
+ - msg_result2 is failed
+ when: can_toast == False
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_unzip/aliases b/ansible_collections/community/windows/tests/integration/targets/win_unzip/aliases
new file mode 100644
index 000000000..4f4664b68
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_unzip/aliases
@@ -0,0 +1 @@
+shippable/windows/group5
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_unzip/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_unzip/defaults/main.yml
new file mode 100644
index 000000000..52d808d88
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_unzip/defaults/main.yml
@@ -0,0 +1 @@
+win_unzip_dir: '{{ remote_tmp_dir }}\win_unzip .ÅÑŚÌβŁÈ [$!@^&test(;)]'
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_unzip/files/create_crafty_zip_files.py b/ansible_collections/community/windows/tests/integration/targets/win_unzip/files/create_crafty_zip_files.py
new file mode 100644
index 000000000..8845b4862
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_unzip/files/create_crafty_zip_files.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env 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)
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+import os
+import shutil
+import sys
+import zipfile
+
+# Each key is a zip file and the vaule is the list of files that will be created
+# and placed in the archive
+zip_files = {
+ 'hat1': [r'hat/..\rabbit.txt'],
+ 'hat2': [r'hat/..\..\rabbit.txt'],
+ 'handcuffs': [r'..\..\houidini.txt'],
+ 'prison': [r'..\houidini.txt'],
+}
+
+# Accept an argument of where to create the files, defaulting to
+# the current working directory.
+try:
+ output_dir = sys.argv[1]
+except IndexError:
+ output_dir = os.getcwd()
+
+if not os.path.isdir(output_dir):
+ os.mkdir(output_dir)
+
+os.chdir(output_dir)
+
+for name, files in zip_files.items():
+ # Create the files to go in the zip archive
+ for entry in files:
+ dirname = os.path.dirname(entry)
+ if dirname:
+ if os.path.isdir(dirname):
+ shutil.rmtree(dirname)
+ os.mkdir(dirname)
+
+ with open(entry, 'w') as e:
+ e.write('escape!\n')
+
+ # Create the zip archive with the files
+ filename = '%s.zip' % name
+ if os.path.isfile(filename):
+ os.unlink(filename)
+
+ with zipfile.ZipFile(filename, 'w') as zf:
+ for entry in files:
+ zf.write(entry)
+
+ # Cleanup
+ if dirname:
+ shutil.rmtree(dirname)
+
+ for entry in files:
+ try:
+ os.unlink(entry)
+ except OSError:
+ pass
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_unzip/files/create_zip.py b/ansible_collections/community/windows/tests/integration/targets/win_unzip/files/create_zip.py
new file mode 100644
index 000000000..41b6ff068
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_unzip/files/create_zip.py
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2019, Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import sys
+import tempfile
+import zipfile
+
+
+def main():
+ filename = b"caf\xc3\xa9.txt"
+
+ with tempfile.NamedTemporaryFile() as temp:
+ with open(temp.name, mode="wb") as fd:
+ fd.write(filename)
+
+ with open(sys.argv[1], mode="wb") as fd:
+ with zipfile.ZipFile(fd, "w") as zip:
+ zip.write(temp.name, filename.decode('utf-8'))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_unzip/meta/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_unzip/meta/main.yml
new file mode 100644
index 000000000..9f37e96cd
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_unzip/meta/main.yml
@@ -0,0 +1,2 @@
+dependencies:
+- setup_remote_tmp_dir
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_unzip/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_unzip/tasks/main.yml
new file mode 100644
index 000000000..82054d1f4
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_unzip/tasks/main.yml
@@ -0,0 +1,171 @@
+- name: create test directory
+ ansible.windows.win_file:
+ path: '{{ win_unzip_dir }}\output'
+ state: directory
+
+- name: create local zip file with non-ascii chars
+ script: create_zip.py {{ output_dir + '/win_unzip.zip' | quote }}
+ delegate_to: localhost
+
+- name: copy across zip to Windows host
+ ansible.windows.win_copy:
+ src: '{{ output_dir }}/win_unzip.zip'
+ dest: '{{ win_unzip_dir }}\win_unzip.zip'
+
+- name: unarchive zip (check)
+ win_unzip:
+ src: '{{ win_unzip_dir }}\win_unzip.zip'
+ dest: '{{ win_unzip_dir }}\output'
+ register: unzip_check
+ check_mode: yes
+
+- name: get result of unarchive zip (check)
+ ansible.windows.win_stat:
+ path: '{{ win_unzip_dir }}\output\café.txt'
+ register: unzip_actual_check
+
+- name: assert result of unarchive zip (check)
+ assert:
+ that:
+ - unzip_check is changed
+ - not unzip_check.removed
+ - not unzip_actual_check.stat.exists
+
+- name: unarchive zip
+ win_unzip:
+ src: '{{ win_unzip_dir }}\win_unzip.zip'
+ dest: '{{ win_unzip_dir }}\output'
+ register: unzip
+
+- name: get result of unarchive zip
+ ansible.windows.slurp:
+ path: '{{ win_unzip_dir }}\output\café.txt'
+ register: unzip_actual
+
+- name: assert result of unarchive zip
+ assert:
+ that:
+ - unzip is changed
+ - not unzip.removed
+ - unzip_actual.content | b64decode == 'café.txt'
+
+# Module is not idempotent, will always change without creates
+- name: unarchive zip again without creates
+ win_unzip:
+ src: '{{ win_unzip_dir }}\win_unzip.zip'
+ dest: '{{ win_unzip_dir }}\output'
+ register: unzip_again
+
+- name: assert unarchive zip again without creates
+ assert:
+ that:
+ - unzip_again is changed
+ - not unzip_again.removed
+
+- name: unarchive zip with creates
+ win_unzip:
+ src: '{{ win_unzip_dir }}\win_unzip.zip'
+ dest: '{{ win_unzip_dir }}\outout'
+ creates: '{{ win_unzip_dir }}\output\café.txt'
+ register: unzip_again_creates
+
+- name: assert unarchive zip with creates
+ assert:
+ that:
+ - not unzip_again_creates is changed
+ - not unzip_again_creates.removed
+
+- name: unarchive zip with delete (check)
+ win_unzip:
+ src: '{{ win_unzip_dir }}\win_unzip.zip'
+ dest: '{{ win_unzip_dir }}\output'
+ delete_archive: yes
+ register: unzip_delete_check
+ check_mode: yes
+
+- name: get result of unarchive zip with delete (check)
+ ansible.windows.win_stat:
+ path: '{{ win_unzip_dir }}\win_unzip.zip'
+ register: unzip_delete_actual_check
+
+- name: assert unarchive zip with delete (check)
+ assert:
+ that:
+ - unzip_delete_check is changed
+ - unzip_delete_check.removed
+ - unzip_delete_actual_check.stat.exists
+
+- name: unarchive zip with delete
+ win_unzip:
+ src: '{{ win_unzip_dir }}\win_unzip.zip'
+ dest: '{{ win_unzip_dir }}\output'
+ delete_archive: yes
+ register: unzip_delete
+
+- name: get result of unarchive zip with delete
+ ansible.windows.win_stat:
+ path: '{{ win_unzip_dir }}\win_unzip.zip'
+ register: unzip_delete_actual
+
+- name: assert unarchive zip with delete
+ assert:
+ that:
+ - unzip_delete is changed
+ - unzip_delete.removed
+ - not unzip_delete_actual.stat.exists
+
+# Path traversal tests (CVE-2020-1737)
+- name: Create zip files
+ script: create_crafty_zip_files.py {{ output_dir }}
+ delegate_to: localhost
+
+- name: Copy zip files to Windows host
+ ansible.windows.win_copy:
+ src: "{{ output_dir }}/{{ item }}.zip"
+ dest: "{{ win_unzip_dir }}/"
+ loop:
+ - hat1
+ - hat2
+ - handcuffs
+ - prison
+
+- name: Perform first trick
+ win_unzip:
+ src: '{{ win_unzip_dir }}\hat1.zip'
+ dest: '{{ win_unzip_dir }}\output'
+ register: hat_trick1
+
+- name: Check for file
+ ansible.windows.win_stat:
+ path: '{{ win_unzip_dir }}\output\rabbit.txt'
+ register: rabbit
+
+- name: Perform next tricks (which should all fail)
+ win_unzip:
+ src: '{{ win_unzip_dir }}\{{ item }}.zip'
+ dest: '{{ win_unzip_dir }}\output'
+ ignore_errors: yes
+ register: escape
+ loop:
+ - hat2
+ - handcuffs
+ - prison
+
+- name: Search for files
+ ansible.windows.win_find:
+ recurse: yes
+ paths:
+ - '{{ win_unzip_dir }}'
+ patterns:
+ - '*houdini.txt'
+ - '*rabbit.txt'
+ register: files
+
+- name: Check results
+ assert:
+ that:
+ - rabbit.stat.exists
+ - hat_trick1 is success
+ - escape.results | map(attribute='failed') | unique | list == [True]
+ - files.matched == 1
+ - files.files[0]['filename'] == 'rabbit.txt'
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_user_profile/aliases b/ansible_collections/community/windows/tests/integration/targets/win_user_profile/aliases
new file mode 100644
index 000000000..215e0b069
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_user_profile/aliases
@@ -0,0 +1 @@
+shippable/windows/group4
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_user_profile/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_user_profile/tasks/main.yml
new file mode 100644
index 000000000..67a9bccc9
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_user_profile/tasks/main.yml
@@ -0,0 +1,42 @@
+---
+- name: set custom user facts
+ set_fact:
+ test_username: ansible_test
+ test_password: '{{ "password123!" + lookup("password", "/dev/null chars=ascii_letters,digits length=9") }}'
+
+- name: create test account
+ ansible.windows.win_user:
+ name: '{{ test_username }}'
+ password: '{{ test_password }}'
+ state: present
+ register: test_username_info
+
+- block:
+ - name: check if profile exists
+ ansible.windows.win_stat:
+ path: C:\temp\{{ test_username }}
+ register: profile_path
+
+ - name: assert that profile doesn't exist before the test
+ assert:
+ that:
+ - not profile_path.stat.exists
+
+ - name: run tests
+ include_tasks: tests.yml
+
+ always:
+ - name: remove test account
+ ansible.windows.win_user:
+ name: '{{ test_username }}'
+ state: absent
+
+ - name: remove test account profile
+ win_user_profile:
+ name: '{{ item }}'
+ state: absent
+ remove_multiple: True
+ with_items:
+ - '{{ test_username }}'
+ - '{{ test_username }}.000'
+ - test_username_profile
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_user_profile/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_user_profile/tasks/tests.yml
new file mode 100644
index 000000000..52e8754b9
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_user_profile/tasks/tests.yml
@@ -0,0 +1,374 @@
+---
+- name: create profile (check mode)
+ win_user_profile:
+ username: '{{ test_username }}'
+ state: present
+ register: create_profile_check
+ check_mode: True
+
+- name: check if profile was created (check mode)
+ ansible.windows.win_stat:
+ path: C:\Users\{{ test_username }}
+ register: create_profile_actual_check
+
+- name: assert create profile (check mode)
+ assert:
+ that:
+ - create_profile_check is changed
+ - create_profile_check.path|lower == "c:\\users\\" + test_username
+ - not create_profile_actual_check.stat.exists
+
+- name: create profile
+ win_user_profile:
+ username: '{{ test_username }}'
+ state: present
+ register: create_profile
+
+- name: check if profile was created
+ ansible.windows.win_stat:
+ path: C:\Users\{{ test_username }}
+ register: create_profile_actual
+
+- name: assert create profile
+ assert:
+ that:
+ - create_profile is changed
+ - create_profile.path|lower == "c:\\users\\" + test_username
+ - create_profile_actual.stat.exists
+
+- name: create profile (idempotent)
+ win_user_profile:
+ username: '{{ test_username }}'
+ state: present
+ register: create_profile_again
+
+- name: assert create profile (idempotent)
+ assert:
+ that:
+ - not create_profile_again is changed
+ - create_profile_again.path|lower == "c:\\users\\" + test_username
+
+- name: remove profile (check mode)
+ win_user_profile:
+ username: '{{ test_username }}'
+ state: absent
+ register: remove_profile_check
+ check_mode: True
+
+- name: check if profile was removed (check mode)
+ ansible.windows.win_stat:
+ path: C:\Users\{{ test_username }}
+ register: remove_profile_actual_check
+
+- name: assert remove profile (check mode)
+ assert:
+ that:
+ - remove_profile_check is changed
+ - remove_profile_check.path|lower == "c:\\users\\" + test_username
+ - remove_profile_actual_check.stat.exists
+
+- name: remove profile
+ win_user_profile:
+ username: '{{ test_username }}'
+ state: absent
+ register: remove_profile
+
+- name: check if profile was removed
+ ansible.windows.win_stat:
+ path: C:\Users\{{ test_username }}
+ register: remove_profile_actual
+
+- name: assert remove profile
+ assert:
+ that:
+ - remove_profile is changed
+ - remove_profile.path|lower == "c:\\users\\" + test_username
+ - not remove_profile_actual.stat.exists
+
+- name: remove profile (idempotent)
+ win_user_profile:
+ username: '{{ test_username }}'
+ state: absent
+ register: remove_profile_again
+
+- name: assert remove profile (idempotent)
+ assert:
+ that:
+ - not remove_profile_again is changed
+ - remove_profile_again.path == None
+
+- name: create profile with specific base path
+ win_user_profile:
+ username: '{{ test_username }}'
+ name: test_username_profile
+ state: present
+ register: create_profile_basename
+
+- name: check if profile with specific base path was created
+ ansible.windows.win_stat:
+ path: C:\Users\test_username_profile
+ register: create_profile_basename_actual
+
+- name: assert create profile with specific base path
+ assert:
+ that:
+ - create_profile_basename is changed
+ - create_profile_basename.path|lower == "c:\\users\\test_username_profile"
+ - create_profile_basename_actual.stat.exists
+
+- name: remove profile with specific base path
+ win_user_profile:
+ username: '{{ test_username }}'
+ state: absent
+ register: remove_profile_basename
+
+- name: check if profile with specific base path was removed
+ ansible.windows.win_stat:
+ path: C:\Users\test_username_profile
+ register: remove_profile_basename_actual
+
+- name: assert remove profile with specific base path
+ assert:
+ that:
+ - remove_profile_basename is changed
+ - remove_profile_basename.path|lower == "c:\\users\\test_username_profile"
+ - not remove_profile_basename_actual.stat.exists
+
+- name: create dummy profile folder
+ ansible.windows.win_file:
+ path: C:\Users\{{ test_username }}
+ state: directory
+
+- block:
+ - name: create profile folder with conflict (check mode)
+ win_user_profile:
+ username: '{{ test_username }}'
+ state: present
+ register: create_profile_conflict_check
+ check_mode: True
+
+ - name: get result of create profile folder with conflict (check mode)
+ ansible.windows.win_stat:
+ path: C:\Users\{{ test_username }}.000
+ register: create_profile_conflict_actual_check
+
+ - name: assert create profile folder with conflict (check mode)
+ assert:
+ that:
+ - create_profile_conflict_check is changed
+ # The check mode path calc is dumb, doesn't check for conflicts
+ - create_profile_conflict_check.path|lower == "c:\\users\\" + test_username
+ - not create_profile_conflict_actual_check.stat.exists
+
+ - name: create profile folder with conflict
+ win_user_profile:
+ username: '{{ test_username }}'
+ state: present
+ register: create_profile_conflict
+
+ - name: get result of create profile with conflict
+ ansible.windows.win_stat:
+ path: C:\Users\{{ test_username }}.000
+ register: create_profile_conflict_actual
+
+ - name: assert create profile folder with conflict
+ assert:
+ that:
+ - create_profile_conflict is changed
+ - create_profile_conflict.path|lower == "c:\\users\\" + test_username + ".000"
+ - create_profile_conflict_actual.stat.exists
+
+ - name: remove profile with conflict
+ win_user_profile:
+ username: '{{ test_username }}'
+ state: absent
+ register: remove_profile_conflict
+
+ - name: get result of profile folder after remove
+ ansible.windows.win_stat:
+ path: C:\Users\{{ test_username }}.000
+ register: remove_profile_conflict_actual
+
+ - name: get result of dummy folder after remove
+ ansible.windows.win_stat:
+ path: C:\Users\{{ test_username }}
+ register: remove_profile_conflict_dummy
+
+ - name: assert remove profile with conflict
+ assert:
+ that:
+ - remove_profile_conflict is changed
+ - remove_profile_conflict.path|lower == "c:\\users\\" + test_username + ".000"
+ - not remove_profile_conflict_actual.stat.exists
+ - remove_profile_conflict_dummy.stat.exists
+
+ always:
+ - name: remove dummy profile folder
+ ansible.windows.win_file:
+ path: C:\Users\{{ test_username }}
+ state: absent
+
+- name: create profile for deleted user by sid test
+ win_user_profile:
+ username: '{{ test_username_info.sid }}'
+ state: present
+
+- name: delete user for deleted user with sid test
+ ansible.windows.win_user:
+ name: '{{ test_username }}'
+ state: absent
+
+- name: remove profile for remove profile by sid test
+ win_user_profile:
+ username: '{{ test_username_info.sid }}'
+ state: absent
+ register: remove_profile_deleted_sid
+
+- name: check if profile was deleted for deleted user using a SID
+ ansible.windows.win_stat:
+ path: C:\Users\{{ test_username }}
+ register: remove_profile_deleted_sid_actual
+
+- name: assert remove profile for deleted user using a SID
+ assert:
+ that:
+ - remove_profile_deleted_sid is changed
+ - remove_profile_deleted_sid.path|lower == "c:\\users\\" + test_username
+ - not remove_profile_deleted_sid_actual.stat.exists
+
+- name: recreate user for deleted user by name test
+ ansible.windows.win_user:
+ name: '{{ test_username }}'
+ password: '{{ test_password }}'
+ state: present
+ register: test_orphan_user1
+
+- name: create profile for deleted user by name test
+ win_user_profile:
+ username: '{{ test_username }}'
+ state: present
+
+- name: delete user for remove profile by name test
+ ansible.windows.win_user:
+ name: '{{ test_username }}'
+ state: absent
+
+- name: remove profile for deleted user using a name
+ win_user_profile:
+ name: '{{ test_username }}'
+ state: absent
+ register: remove_profile_deleted_name
+
+- name: check if profile was deleted for deleted user using a name
+ ansible.windows.win_stat:
+ path: C:\Users\{{ test_username }}
+ register: remove_profile_deleted_name_actual
+
+- name: assert remove profile for deleted user using a name
+ assert:
+ that:
+ - remove_profile_deleted_name is changed
+ - remove_profile_deleted_name.path|lower == "c:\\users\\" + test_username
+ - not remove_profile_deleted_name_actual.stat.exists
+
+- name: remove profile for deleted user using a name (idempotent)
+ win_user_profile:
+ name: '{{ test_username }}'
+ state: absent
+ register: remove_profile_deleted_name_again
+
+- name: assert remove profile for deleted user using a name (idempotent)
+ assert:
+ that:
+ - not remove_profile_deleted_name_again is changed
+
+- name: recreate user for remove multiple user test
+ ansible.windows.win_user:
+ name: '{{ test_username }}'
+ password: '{{ test_password }}'
+ state: present
+ register: test_orphan_user1
+
+- name: create new profile for remove multiple user test
+ win_user_profile:
+ username: '{{ test_username }}'
+ state: present
+ register: orphan_user1_profile
+
+- name: remove user 1 for remove multiple user test
+ ansible.windows.win_user:
+ name: '{{ test_username }}'
+ state: absent
+
+# win_file has issues with paths exceeding MAX_PATH, need to use rmdir instead
+- name: remove profile folder for user 1
+ ansible.windows.win_shell: rmdir /S /Q {{ orphan_user1_profile.path}}
+ args:
+ executable: cmd.exe
+
+- name: create user 2 for remove multiple user test
+ ansible.windows.win_user:
+ name: '{{ test_username }}'
+ password: '{{ test_password }}'
+ state: present
+ register: test_orphan_user2
+
+- name: create new profile for orphan user 2
+ win_user_profile:
+ username: '{{ test_username }}'
+ state: present
+ register: orphan_user2_profile
+
+- name: remove orphan user 2 for remove multiple user test
+ ansible.windows.win_user:
+ name: '{{ test_username }}'
+ state: present
+
+- name: fail to remove multiple profiles without flag
+ win_user_profile:
+ name: '{{ test_username }}'
+ state: absent
+ register: fail_remove_multiple
+ ignore_errors: True
+
+- name: check if profile was removed
+ ansible.windows.win_stat:
+ path: C:\Users\{{ test_username }}
+ register: fail_remove_multiple_actual
+
+- name: assert that profile was not actually deleted
+ assert:
+ that:
+ - fail_remove_multiple.msg == "Found multiple profiles matching the path 'C:\\Users\\" + test_username + "', set 'remove_multiple=True' to remove all the profiles for this match"
+ - fail_remove_multiple_actual.stat.exists
+
+- name: remove multiple profiles
+ win_user_profile:
+ name: '{{ test_username }}'
+ state: absent
+ remove_multiple: True
+ register: remove_multiple
+
+- name: get result of remove multiple profiles
+ ansible.windows.win_stat:
+ path: C:\Users\{{ test_username }}
+ register: remove_multiple_actual
+
+- name: check that orphan user 1 reg profile has been removed
+ ansible.windows.win_reg_stat:
+ path: HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\{{ test_orphan_user1.sid }}
+ register: remove_orphan1_actual
+
+- name: check that orphan user 2 reg profile has been removed
+ ansible.windows.win_reg_stat:
+ path: HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\{{ test_orphan_user2.sid }}
+ register: remove_orphan2_actual
+
+- name: assert remove multiple profiles
+ assert:
+ that:
+ - remove_multiple is changed
+ - remove_multiple.path|lower == "c:\\users\\" + test_username
+ - not remove_multiple_actual.stat.exists
+ - not remove_orphan1_actual.exists
+ - not remove_orphan2_actual.exists
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_wait_for_process/aliases b/ansible_collections/community/windows/tests/integration/targets/win_wait_for_process/aliases
new file mode 100644
index 000000000..215e0b069
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_wait_for_process/aliases
@@ -0,0 +1 @@
+shippable/windows/group4
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_wait_for_process/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_wait_for_process/tasks/main.yml
new file mode 100644
index 000000000..3ec692cb4
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_wait_for_process/tasks/main.yml
@@ -0,0 +1,201 @@
+---
+- name: Get powershell version
+ ansible.windows.win_shell: $PSVersionTable.PSVersion.Major
+ register: powershell_version
+
+- name: Ensure Spooler service is started
+ ansible.windows.win_service:
+ name: Spooler
+ state: started
+
+- name: Wait for non-existing process to not exist
+ win_wait_for_process:
+ process_name_exact:
+ - ansible_foobar
+ timeout: 30
+ state: absent
+ register: absent_nonexisting_process
+
+- assert:
+ that:
+ - absent_nonexisting_process is success
+ - absent_nonexisting_process is not changed
+ - absent_nonexisting_process.elapsed > 0
+ - absent_nonexisting_process.elapsed < 30
+ - absent_nonexisting_process.matched_processes|length == 0
+
+- name: Wait for non-existing process until timeout
+ win_wait_for_process:
+ process_name_exact: ansible_foobar
+ timeout: 30
+ state: present
+ ignore_errors: yes
+ register: present_nonexisting_process
+
+- assert:
+ that:
+ - present_nonexisting_process is failed
+ - present_nonexisting_process is not changed
+ - present_nonexisting_process.elapsed > 30
+ - present_nonexisting_process.msg == 'Timed out while waiting for process(es) to start'
+ - present_nonexisting_process.matched_processes|length == 0
+
+- name: Wait for existing process to exist
+ win_wait_for_process:
+ process_name_exact: spoolsv
+ timeout: 30
+ state: present
+ register: present_existing_process
+
+- assert:
+ that:
+ - present_existing_process is success
+ - present_existing_process is not changed
+ - present_existing_process.elapsed > 0
+ - present_existing_process.elapsed < 30
+ - present_existing_process.matched_processes|length > 0
+
+- name: Wait for existing process until timeout
+ win_wait_for_process:
+ process_name_exact:
+ - spoolsv
+ timeout: 30
+ state: absent
+ ignore_errors: yes
+ register: absent_existing_process
+
+- assert:
+ that:
+ - absent_existing_process is failed
+ - absent_existing_process is not changed
+ - absent_existing_process.elapsed > 30
+ - absent_existing_process.matched_processes|length > 0
+ - absent_existing_process.msg == 'Timeout while waiting for process(es) to stop'
+
+- name: Wait for existing process to exist (using owner)
+ win_wait_for_process:
+ process_name_exact: spoolsv
+ owner: SYSTEM
+ timeout: 30
+ state: present
+ ignore_errors: yes
+ register: present_existing_owner_process
+
+- assert:
+ that:
+ - present_existing_owner_process is success
+ - present_existing_owner_process is not changed
+ - present_existing_owner_process.elapsed > 0
+ - present_existing_owner_process.elapsed < 30
+ - present_existing_owner_process.matched_processes|length > 0
+ when: powershell_version.stdout_lines[0]|int >= 4
+
+- assert:
+ that:
+ - present_existing_owner_process is failed
+ - present_existing_owner_process is not changed
+ - present_existing_owner_process.elapsed == 0
+ - present_existing_owner_process.matched_processes|length == 0
+ - present_existing_owner_process.msg == "This version of Powershell does not support filtering processes by 'owner'."
+ when: powershell_version.stdout_lines[0]|int < 4
+
+- name: Wait for Spooler service to stop
+ win_wait_for_process:
+ process_name_exact:
+ - spoolsv
+ - other_process # Tests that just 1 needs to match
+ timeout: 60
+ state: absent
+ async: 30
+ poll: 0
+ register: spoolsv_process
+
+- name: Stop the Spooler service
+ ansible.windows.win_service:
+ name: Spooler
+ force_dependent_services: yes
+ state: stopped
+
+- name: Check on async task
+ async_status:
+ jid: '{{ spoolsv_process.ansible_job_id }}'
+ until: absent_spoolsv_process is finished
+ retries: 20
+ register: absent_spoolsv_process
+
+- assert:
+ that:
+ - absent_spoolsv_process is success
+ - absent_spoolsv_process is not changed
+ - absent_spoolsv_process is finished
+ - absent_spoolsv_process.elapsed > 0
+ - absent_spoolsv_process.elapsed < 30
+ - absent_spoolsv_process.matched_processes|length == 1
+
+- name: Wait for Spooler service to start
+ win_wait_for_process:
+ process_name_exact: spoolsv
+ timeout: 60
+ state: present
+ async: 60
+ poll: 0
+ register: spoolsv_process
+
+- name: Start the spooler service
+ ansible.windows.win_service:
+ name: Spooler
+ force_dependent_services: yes
+ state: started
+
+- name: Check on async task
+ async_status:
+ jid: '{{ spoolsv_process.ansible_job_id }}'
+ until: present_spoolsv_process is finished
+ retries: 10
+ register: present_spoolsv_process
+
+- assert:
+ that:
+ - present_spoolsv_process is success
+ - present_spoolsv_process is not changed
+ - present_spoolsv_process is finished
+ - present_spoolsv_process.elapsed > 0
+ - present_spoolsv_process.elapsed < 60
+ - present_spoolsv_process.matched_processes|length == 1
+
+- name: Start a new long-running process
+ ansible.windows.win_shell: |
+ Start-Sleep -Seconds 15
+ async: 40
+ poll: 0
+ register: sleep_pid
+
+- name: Wait for PID to start
+ win_wait_for_process:
+ pid: '{{ sleep_pid.ansible_async_watchdog_pid }}'
+ timeout: 20
+ state: present
+ register: present_sleep_pid
+
+- assert:
+ that:
+ - present_sleep_pid is success
+ - present_sleep_pid is not changed
+ - present_sleep_pid.elapsed > 0
+ - present_sleep_pid.elapsed < 15
+ - present_sleep_pid.matched_processes|length == 1
+
+- name: Wait for PID to stop
+ win_wait_for_process:
+ pid: '{{ sleep_pid.ansible_async_watchdog_pid }}'
+ timeout: 20
+ state: absent
+ register: absent_sleep_pid
+
+- assert:
+ that:
+ - absent_sleep_pid is success
+ - absent_sleep_pid is not changed
+ - absent_sleep_pid.elapsed > 0
+ - absent_sleep_pid.elapsed < 15
+ - absent_sleep_pid.matched_processes|length == 1
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_wakeonlan/aliases b/ansible_collections/community/windows/tests/integration/targets/win_wakeonlan/aliases
new file mode 100644
index 000000000..3cf5b97e8
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_wakeonlan/aliases
@@ -0,0 +1 @@
+shippable/windows/group3
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_wakeonlan/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_wakeonlan/tasks/main.yml
new file mode 100644
index 000000000..169362b00
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_wakeonlan/tasks/main.yml
@@ -0,0 +1,9 @@
+- name: Send a magic Wake-on-LAN packet to 00:00:5E:00:53:66
+ win_wakeonlan:
+ mac: 00:00:5E:00:53:66
+ broadcast: 192.0.2.255
+
+- name: Send a magic Wake-On-LAN packet on port 9 to 00-00-5E-00-53-66
+ win_wakeonlan:
+ mac: 00-00-5E-00-53-66
+ port: 9
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_xml/aliases b/ansible_collections/community/windows/tests/integration/targets/win_xml/aliases
new file mode 100644
index 000000000..3cf5b97e8
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_xml/aliases
@@ -0,0 +1 @@
+shippable/windows/group3
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_xml/files/books.xml b/ansible_collections/community/windows/tests/integration/targets/win_xml/files/books.xml
new file mode 100644
index 000000000..e38ee15d4
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_xml/files/books.xml
@@ -0,0 +1,10 @@
+<?xml version='1.0' encoding='utf-8'?>
+<books>
+ <works lang="en">
+ <title lang="en" isbn13="123412341234X">A Great Book</title>
+ <title lang="en" isbn13="1234109823400">Best Book Ever</title>
+ <title lang="en" isbn13="123412121234X">Worst Book Ever</title>
+ <title lang="en" isbn13="423412341234X">Another Book</title>
+ <title lang="en" isbn13="523412341234X">Worst Book Ever Two</title>
+ </works>
+</books>
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_xml/files/config.xml b/ansible_collections/community/windows/tests/integration/targets/win_xml/files/config.xml
new file mode 100644
index 000000000..b5241b351
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_xml/files/config.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<config>
+ <string key="foo">bar</string>
+ <setting></setting>
+</config>
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_xml/files/log4j.xml b/ansible_collections/community/windows/tests/integration/targets/win_xml/files/log4j.xml
new file mode 100644
index 000000000..54b76cf7f
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_xml/files/log4j.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">
+ <appender name="stdout" class="org.apache.log4j.ConsoleAppender" >
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="[%d{dd/MM/yy hh:mm:ss:sss z}] %5p %c{2}: %m%n"/>
+ </layout>
+ </appender>
+
+ <appender name="file" class="org.apache.log4j.DailyRollingFileAppender">
+ <param name="append" value="true" />
+ <param name="encoding" value="UTF-8" />
+ <param name="file" value="mylogfile.log" />
+ <param name="DatePattern" value="'.'yyyy-MM-dd" />
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="[%-25d{ISO8601}] %-5p %x %C{1} -- %m\n" />
+ </layout>
+ </appender>
+
+ <logger name="org.springframework.security.web.FilterChainProxy" additivity="false">
+ <level value="error"/>
+ <appender-ref ref="file" />
+ </logger>
+
+ <logger name="org.springframework.security.web.context.HttpSessionSecurityContextRepository" additivity="false">
+ <level value="error"/>
+ <appender-ref ref="file" />
+ </logger>
+
+ <logger name="org.springframework.security.web.context.SecurityContextPersistenceFilter" additivity="false">
+ <level value="error"/>
+ <appender-ref ref="file" />
+ </logger>
+
+ <logger name="org.springframework.security.web.access.intercept" additivity="false">
+ <level value="error"/>
+ <appender-ref ref="stdout" />
+ </logger>
+
+ <logger name="org.apache.commons.digester" additivity="false">
+ <level value="info"/>
+ <appender-ref ref="stdout" />
+ </logger>
+
+ <root>
+ <priority value="debug"/>
+ <appender-ref ref="stdout"/>
+ </root>
+</log4j:configuration>
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_xml/files/plane.zip b/ansible_collections/community/windows/tests/integration/targets/win_xml/files/plane.zip
new file mode 100644
index 000000000..8157182aa
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_xml/files/plane.zip
Binary files differ
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_xml/meta/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_xml/meta/main.yml
new file mode 100644
index 000000000..9f37e96cd
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_xml/meta/main.yml
@@ -0,0 +1,2 @@
+dependencies:
+- setup_remote_tmp_dir
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_xml/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_xml/tasks/main.yml
new file mode 100644
index 000000000..b51dc563f
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_xml/tasks/main.yml
@@ -0,0 +1,361 @@
+# test code for the Windows xml module
+# (c) 2017, Richard Levenberg <richard.levenberg@cosocloud.com>
+
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+- name: copy a test .xml file
+ ansible.windows.win_copy:
+ src: config.xml
+ dest: "{{ remote_tmp_dir }}\\config.xml"
+
+- name: add an element that only has a text child node
+ win_xml:
+ path: "{{ remote_tmp_dir }}\\config.xml"
+ fragment: '<string key="answer">42</string>'
+ xpath: '/config'
+ register: element_add_result
+
+- name: check element add result
+ assert:
+ that:
+ - element_add_result is changed
+
+- name: try to add the element that only has a text child node again
+ win_xml:
+ path: "{{ remote_tmp_dir }}\\config.xml"
+ fragment: '<string key="answer">42</string>'
+ xpath: '/config'
+ register: element_add_result_second
+
+- name: check element add result
+ assert:
+ that:
+ - not element_add_result_second is changed
+
+- name: copy a test log4j.xml
+ ansible.windows.win_copy:
+ src: log4j.xml
+ dest: "{{ remote_tmp_dir }}\\log4j.xml"
+
+- name: change an attribute to fatal logging
+ win_xml:
+ path: "{{ remote_tmp_dir }}\\log4j.xml"
+ xpath: '/log4j:configuration/logger[@name="org.apache.commons.digester"]/level'
+ type: attribute
+ attribute: 'value'
+ fragment: 'FATAL'
+
+- name: try to change the attribute again
+ win_xml:
+ path: "{{ remote_tmp_dir }}\\log4j.xml"
+ xpath: '/log4j:configuration/logger[@name="org.apache.commons.digester"]/level'
+ type: attribute
+ attribute: 'value'
+ fragment: 'FATAL'
+ register: attribute_changed_result
+
+- name: check attribute change result
+ assert:
+ that:
+ - attribute_changed_result is not changed
+
+- name: try to add a new attribute
+ win_xml:
+ path: "{{ remote_tmp_dir }}\\config.xml"
+ xpath: '/config/string[@key="foo"]'
+ type: attribute
+ attribute: spam
+ fragment: 'ham'
+ register: element_add_attribute_result
+
+- name: check element add attribute result
+ assert:
+ that:
+ - element_add_attribute_result is changed
+
+- name: try to set the added attribute to the same value again
+ win_xml:
+ path: "{{ remote_tmp_dir }}\\config.xml"
+ xpath: '/config/string[@key="foo"]'
+ type: attribute
+ attribute: spam
+ fragment: 'ham'
+ register: element_add_attribute_result_second
+
+- name: check element add attribute result
+ assert:
+ that:
+ - not element_add_attribute_result_second is changed
+
+- name: try to add a new element in empty element
+ win_xml:
+ path: "{{ remote_tmp_dir }}\\config.xml"
+ xpath: '/config/setting'
+ fragment: "<property />"
+ type: element
+ register: element_add_empty_element
+
+- name: check element add in empty element result
+ assert:
+ that:
+ - element_add_empty_element is changed
+
+- name: try to add a new element in empty element again
+ win_xml:
+ path: "{{ remote_tmp_dir }}\\config.xml"
+ xpath: '/config/setting'
+ fragment: "<property />"
+ type: element
+ register: element_add_empty_element_second
+
+- name: check element add in empty element result
+ assert:
+ that:
+ - not element_add_empty_element_second is changed
+
+# This testing is for https://github.com/ansible/ansible/issues/48471
+# The issue was that an .xml with no encoding declaration, but a UTF8 BOM
+# with some UTF-8 characters was being written out with garbage characters.
+# The characters added by win_xml were not UTF-8 characters.
+
+- name: copy test files (https://github.com/ansible/ansible/issues/48471)
+ ansible.windows.win_copy:
+ src: plane.zip
+ dest: "{{ remote_tmp_dir }}\\plane.zip"
+
+- name: unarchive the test files
+ win_unzip:
+ src: "{{ remote_tmp_dir }}\\plane.zip"
+ dest: "{{ remote_tmp_dir }}\\"
+
+- name: change a text value in a file with UTF8 BOM and armenian characters in the description
+ win_xml:
+ path: "{{ remote_tmp_dir }}\\plane-utf8-bom-armenian-characters.xml"
+ xpath: '/plane/year'
+ type: text
+ fragment: '1988'
+
+- name: register the sha1 of the new file
+ ansible.windows.win_stat:
+ path: "{{ remote_tmp_dir }}\\plane-utf8-bom-armenian-characters.xml"
+ get_checksum: yes
+ register: sha1_checksum
+
+- name: verify the checksum
+ assert:
+ that:
+ - sha1_checksum.stat.checksum == 'e3e18c3066e1bfce9a5cf87c81353fa174440944'
+
+- name: change a text value in a file with UTF8 BOM and armenian characters in the description
+ win_xml:
+ path: "{{ remote_tmp_dir }}\\plane-utf8-bom-armenian-characters.xml"
+ xpath: '/plane/year'
+ type: text
+ fragment: '1989'
+ backup: yes
+ register: test_backup
+
+- name: check backup_file
+ ansible.windows.win_stat:
+ path: '{{ test_backup.backup_file }}'
+ register: backup_file
+
+- name: Check backup_file
+ assert:
+ that:
+ - test_backup is changed
+ - backup_file.stat.exists == true
+
+- name: change a text value in a file with UTF-16 BE BOM and Chinese characters in the description
+ win_xml:
+ path: "{{ remote_tmp_dir }}\\plane-utf16be-bom-chinese-characters.xml"
+ xpath: '/plane/year'
+ type: text
+ fragment: '1988'
+
+- name: register the sha1 of the new file
+ ansible.windows.win_stat:
+ path: "{{ remote_tmp_dir }}\\plane-utf16be-bom-chinese-characters.xml"
+ get_checksum: yes
+ register: sha1_checksum
+
+- name: verify the checksum
+ assert:
+ that:
+ - sha1_checksum.stat.checksum == 'de86f79b409383447cf4cf112b20af8ffffcfdbf'
+
+# features added ansible 2.8
+# count
+
+- name: count logger nodes in log4j.xml
+ win_xml:
+ path: "{{ remote_tmp_dir }}\\log4j.xml"
+ xpath: //logger
+ count: yes
+ register: logger_node_count
+
+- name: verify node count
+ assert:
+ that:
+ - logger_node_count.count == 5
+
+# multiple attribute change
+- name: ensure //logger/level value attributes are set to debug
+ win_xml:
+ path: "{{ remote_tmp_dir }}\\log4j.xml"
+ xpath: '//logger/level[@value="error"]'
+ type: attribute
+ attribute: value
+ fragment: debug
+ count: yes
+ register: logger_level_value_attrs
+
+- name: verify //logger/level value attributes
+ assert:
+ that:
+ - logger_level_value_attrs.count == 4
+ - logger_level_value_attrs.changed == true
+ - logger_level_value_attrs.msg == 'attribute changed'
+
+- name: ensure //logger/level value attributes are set to debug (idempotency)
+ win_xml:
+ path: "{{ remote_tmp_dir }}\\log4j.xml"
+ xpath: '//logger/level[@value="error"]'
+ type: attribute
+ attribute: value
+ fragment: debug
+ count: yes
+ register: logger_level_value_attrs_again
+
+- name: verify //logger/level value attributes again (idempotency)
+ assert:
+ that:
+ - logger_level_value_attrs_again.count == 0
+ - logger_level_value_attrs_again.changed == false
+ - logger_level_value_attrs_again.msg == 'The supplied xpath did not match any nodes. If this is unexpected, check your xpath is valid for the xml file at supplied path.'
+
+# multiple text nodes
+- name: ensure test books.xml is present
+ ansible.windows.win_copy:
+ src: books.xml
+ dest: '{{ remote_tmp_dir }}\books.xml'
+
+- name: demonstrate multi text replace by replacing all title text elements
+ win_xml:
+ path: '{{ remote_tmp_dir }}\books.xml'
+ xpath: //works/title
+ type: text
+ fragment: _TITLE_TEXT_REMOVED_BY_WIN_XML_MODULE_
+ count: yes
+ register: multi_text
+
+- name: verify multi text change
+ assert:
+ that:
+ - multi_text.changed == true
+ - multi_text.count == 5
+ - multi_text.msg == 'text changed'
+
+- name: demonstrate multi text replace by replacing all title text elements again (idempotency)
+ win_xml:
+ path: '{{ remote_tmp_dir }}\books.xml'
+ xpath: //works/title
+ type: text
+ fragment: _TITLE_TEXT_REMOVED_BY_WIN_XML_MODULE_
+ count: yes
+ register: multi_text_again
+
+- name: verify multi text again change (idempotency)
+ assert:
+ that:
+ - multi_text_again.changed == false
+ - multi_text_again.count == 5
+ - multi_text_again.msg == 'not changed'
+
+# multiple element
+
+#- name: ensure a fresh test books.xml is present
+# ansible.windows.win_copy:
+# src: books.xml
+# dest: '{{ remote_tmp_dir }}\books.xml'
+
+- name: demonstrate multi element should append new information element from fragment
+ win_xml:
+ path: '{{ remote_tmp_dir }}\books.xml'
+ xpath: //works/title
+ type: element
+ fragment: <information>This element added by ansible</information>
+ count: yes
+ register: multi_element
+
+- name: verify multi element
+ assert:
+ that:
+ - multi_element.changed == true
+ - multi_element.count == 5
+ - multi_element.msg == 'element changed'
+
+- name: demonstrate multi element unchanged (idempotency)
+ win_xml:
+ path: '{{ remote_tmp_dir }}\books.xml'
+ xpath: //works/title
+ type: element
+ fragment: <information>This element added by ansible</information>
+ count: yes
+ register: multi_element_again
+
+- name: verify multi element again (idempotency)
+ assert:
+ that:
+ - multi_element_again.changed == false
+ - multi_element_again.count == 5
+ - multi_element_again.msg == 'not changed'
+
+# multiple attributes on differing parent nodes
+
+- name: ensure all attribute lang=nl
+ win_xml:
+ path: '{{ remote_tmp_dir }}\books.xml'
+ xpath: //@lang
+ type: attribute
+ attribute: lang
+ fragment: nl
+ count: yes
+ register: multi_attr
+
+- name: verify multi attribute
+ assert:
+ that:
+ - multi_attr.changed == true
+ - multi_attr.count == 6
+ - multi_attr.msg == 'attribute changed'
+
+- name: ensure all attribute lang=nl (idempotency)
+ win_xml:
+ path: '{{ remote_tmp_dir }}\books.xml'
+ xpath: //@lang
+ type: attribute
+ attribute: lang
+ fragment: nl
+ count: yes
+ register: multi_attr_again
+
+- name: verify multi attribute (idempotency)
+ assert:
+ that:
+ - multi_attr_again.changed == false
+ - multi_attr_again.count == 6
+ - multi_attr_again.msg == 'not changed'
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_zip/aliases b/ansible_collections/community/windows/tests/integration/targets/win_zip/aliases
new file mode 100644
index 000000000..b6fdaeae0
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_zip/aliases
@@ -0,0 +1 @@
+shippable/windows/group5 \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_zip/defaults/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_zip/defaults/main.yml
new file mode 100644
index 000000000..1b2520d5a
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_zip/defaults/main.yml
@@ -0,0 +1,2 @@
+win_zip_name: .ÅÑŚÌβŁÈ [$!@^&test(;)] 👋
+win_zip_dir: '{{ remote_tmp_dir }}\win_zip {{ win_zip_name }}' \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_zip/meta/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_zip/meta/main.yml
new file mode 100644
index 000000000..9f37e96cd
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_zip/meta/main.yml
@@ -0,0 +1,2 @@
+dependencies:
+- setup_remote_tmp_dir
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_zip/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_zip/tasks/main.yml
new file mode 100644
index 000000000..bdf98641a
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_zip/tasks/main.yml
@@ -0,0 +1,165 @@
+---
+- set_fact:
+ zip_info: |
+ param ($Path)
+
+ $ErrorActionPreference = 'Stop'
+ $Ansible.Changed = $false
+
+ $utf8 = New-Object -TypeName Text.UTF8Encoding -ArgumentList $false
+ Add-Type -AssemblyName System.IO.Compression -ErrorAction Stop
+ Add-Type -AssemblyName System.IO.Compression.FileSystem -ErrorAction Stop
+
+ $zip = $null
+ $fs = [IO.File]::OpenRead($Path)
+ try {
+ $zip = New-Object -TypeName IO.Compression.ZipArchive -ArgumentList $fs, 'Read', $false, $utf8
+
+ $zip.Entries | Select-Object -Propert FullName, Length
+ }
+ finally {
+ if ($zip) { $zip.Dispose() }
+ $fs.Dispose()
+ }
+
+- name: create testdir\src directory for CI
+ ansible.windows.win_file:
+ path: '{{ win_zip_dir }}\src\'
+ state: directory
+
+- name: create testdir\zipped directory for CI
+ ansible.windows.win_file:
+ path: '{{ win_zip_dir }}\zipped\'
+ state: directory
+
+- name: create test files for CI
+ ansible.builtin.win_copy:
+ content: |
+ This is a test file.
+ dest: '{{ win_zip_dir }}\src\{{ win_zip_name }}.txt'
+
+# Case01: Check file compression
+- name: compress a file (check)
+ win_zip:
+ src: '{{ win_zip_dir }}\src\{{ win_zip_name }}.txt'
+ dest: '{{ win_zip_dir }}\zipped\test_file.zip'
+ register: zip_check
+ check_mode: yes
+
+- name: get result of compress zip (check)
+ ansible.windows.win_stat:
+ path: '{{ win_zip_dir }}\zipped\test_file.zip'
+ register: zip_actual_check
+
+- name: assert result of zip (check)
+ assert:
+ that:
+ - zip_check is changed
+ - not zip_actual_check.stat.exists
+
+- name: compress a file
+ win_zip:
+ src: '{{ win_zip_dir }}\src\{{ win_zip_name }}.txt'
+ dest: '{{ win_zip_dir }}\zipped\test_file.zip'
+ register: zip
+
+- name: get result of compress zip
+ ansible.windows.win_powershell:
+ script: '{{ zip_info }}'
+ parameters:
+ Path: '{{ win_zip_dir }}\zipped\test_file.zip'
+ register: zip_actual
+
+- name: assert result of zip
+ assert:
+ that:
+ - zip is changed
+ - zip_actual.output | length == 1
+ - zip_actual.output[0]['FullName'] == win_zip_name + '.txt'
+ - zip_actual.output[0]['Length'] == 21
+
+# Case02: Check directory compression
+- name: compress a directory (check)
+ win_zip:
+ src: '{{ win_zip_dir }}\src\'
+ dest: '{{ win_zip_dir }}\test_dir.zip'
+ register: zip_check
+ check_mode: yes
+
+- name: get result of compress zip (check)
+ ansible.windows.win_stat:
+ path: '{{ win_zip_dir }}\test_dir.zip'
+ register: zip_actual_check
+
+- name: assert result of zip (check)
+ assert:
+ that:
+ - zip_check is changed
+ - not zip_actual_check.stat.exists
+
+- name: compress a directory
+ win_zip:
+ src: '{{ win_zip_dir }}\src\'
+ dest: '{{ win_zip_dir }}\test_dir.zip'
+ register: zip
+
+- name: get result of compress zip
+ ansible.windows.win_powershell:
+ script: '{{ zip_info }}'
+ parameters:
+ Path: '{{ win_zip_dir }}\test_dir.zip'
+ register: zip_actual
+
+- name: assert result of zip
+ assert:
+ that:
+ - zip is changed
+ - zip_actual.output | length == 1
+ # Should contain the original base directory
+ - zip_actual.output[0]['FullName'] == "src/" + win_zip_name + '.txt'
+ - zip_actual.output[0]['Length'] == 21
+
+- name: compress a directories contents
+ win_zip:
+ src: '{{ win_zip_dir }}\src\*'
+ dest: '{{ win_zip_dir }}\test_dir_content.zip'
+ register: zip
+
+- name: get result of compress zip
+ ansible.windows.win_powershell:
+ script: '{{ zip_info }}'
+ parameters:
+ Path: '{{ win_zip_dir }}\test_dir_content.zip'
+ register: zip_actual
+
+- name: assert result of zip
+ assert:
+ that:
+ - zip is changed
+ - zip_actual.output | length == 1
+ # Should not contain the original base directory
+ - zip_actual.output[0]['FullName'] == win_zip_name + '.txt'
+ - zip_actual.output[0]['Length'] == 21
+
+- name: compress a file with existing dest (check)
+ win_zip:
+ src: '{{ win_zip_dir }}\src\{{ win_zip_name }}.txt'
+ dest: '{{ win_zip_dir }}\zipped\test_file.zip'
+ register: zip_check
+ check_mode: yes
+
+- name: assert result of zip (check)
+ assert:
+ that:
+ - not zip_check is changed
+
+- name: compress a file to existing dest
+ win_zip:
+ src: '{{ win_zip_dir }}\src\{{ win_zip_name }}.txt'
+ dest: '{{ win_zip_dir }}\zipped\test_file.zip'
+ register: zip
+
+- name: assert result of zip
+ assert:
+ that:
+ - not zip is changed