ansible-core 2.18.5rc1__py3-none-any.whl → 2.19.0b2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (710) hide show
  1. ansible/_internal/__init__.py +53 -0
  2. ansible/_internal/_ansiballz.py +265 -0
  3. ansible/_internal/_collection_proxy.py +47 -0
  4. ansible/_internal/_datatag/__init__.py +0 -0
  5. ansible/_internal/_datatag/_tags.py +130 -0
  6. ansible/_internal/_datatag/_utils.py +19 -0
  7. ansible/_internal/_datatag/_wrappers.py +33 -0
  8. ansible/_internal/_errors/__init__.py +0 -0
  9. ansible/_internal/_errors/_captured.py +128 -0
  10. ansible/_internal/_errors/_handler.py +91 -0
  11. ansible/_internal/_errors/_utils.py +310 -0
  12. ansible/_internal/_json/__init__.py +203 -0
  13. ansible/_internal/_json/_legacy_encoder.py +34 -0
  14. ansible/_internal/_json/_profiles/__init__.py +0 -0
  15. ansible/_internal/_json/_profiles/_cache_persistence.py +55 -0
  16. ansible/_internal/_json/_profiles/_inventory_legacy.py +40 -0
  17. ansible/_internal/_json/_profiles/_legacy.py +197 -0
  18. ansible/_internal/_locking.py +21 -0
  19. ansible/_internal/_plugins/__init__.py +0 -0
  20. ansible/_internal/_plugins/_cache.py +57 -0
  21. ansible/_internal/_task.py +78 -0
  22. ansible/_internal/_templating/__init__.py +10 -0
  23. ansible/_internal/_templating/_access.py +86 -0
  24. ansible/_internal/_templating/_chain_templar.py +63 -0
  25. ansible/_internal/_templating/_datatag.py +95 -0
  26. ansible/_internal/_templating/_engine.py +588 -0
  27. ansible/_internal/_templating/_errors.py +28 -0
  28. ansible/_internal/_templating/_jinja_bits.py +1066 -0
  29. ansible/_internal/_templating/_jinja_common.py +332 -0
  30. ansible/_internal/_templating/_jinja_patches.py +44 -0
  31. ansible/_internal/_templating/_jinja_plugins.py +345 -0
  32. ansible/_internal/_templating/_lazy_containers.py +633 -0
  33. ansible/_internal/_templating/_marker_behaviors.py +103 -0
  34. ansible/_internal/_templating/_transform.py +63 -0
  35. ansible/_internal/_templating/_utils.py +107 -0
  36. ansible/_internal/_wrapt.py +1052 -0
  37. ansible/_internal/_yaml/__init__.py +0 -0
  38. ansible/_internal/_yaml/_constructor.py +240 -0
  39. ansible/_internal/_yaml/_dumper.py +62 -0
  40. ansible/_internal/_yaml/_errors.py +166 -0
  41. ansible/_internal/_yaml/_loader.py +66 -0
  42. ansible/_internal/ansible_collections/ansible/_protomatter/README.md +11 -0
  43. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/action/debug.py +36 -0
  44. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/apply_trust.py +19 -0
  45. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/dump_object.py +18 -0
  46. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/finalize.py +16 -0
  47. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/origin.py +18 -0
  48. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.py +24 -0
  49. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.yml +33 -0
  50. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/tag_names.py +16 -0
  51. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/true_type.py +17 -0
  52. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/unmask.py +49 -0
  53. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.py +21 -0
  54. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.yml +2 -0
  55. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.py +15 -0
  56. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.yml +19 -0
  57. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.py +18 -0
  58. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.yml +19 -0
  59. ansible/cli/__init__.py +159 -89
  60. ansible/cli/_ssh_askpass.py +47 -0
  61. ansible/cli/adhoc.py +14 -7
  62. ansible/cli/arguments/option_helpers.py +154 -7
  63. ansible/cli/config.py +43 -68
  64. ansible/cli/console.py +10 -8
  65. ansible/cli/doc.py +62 -53
  66. ansible/cli/galaxy.py +27 -20
  67. ansible/cli/inventory.py +28 -26
  68. ansible/cli/playbook.py +4 -12
  69. ansible/cli/pull.py +51 -11
  70. ansible/cli/scripts/ansible_connection_cli_stub.py +7 -7
  71. ansible/cli/vault.py +12 -11
  72. ansible/compat/__init__.py +2 -2
  73. ansible/config/base.yml +166 -112
  74. ansible/config/manager.py +52 -49
  75. ansible/constants.py +3 -4
  76. ansible/errors/__init__.py +277 -235
  77. ansible/executor/interpreter_discovery.py +28 -149
  78. ansible/executor/module_common.py +426 -493
  79. ansible/executor/play_iterator.py +22 -27
  80. ansible/executor/playbook_executor.py +11 -11
  81. ansible/executor/powershell/async_watchdog.ps1 +97 -102
  82. ansible/executor/powershell/async_wrapper.ps1 +202 -151
  83. ansible/executor/powershell/become_wrapper.ps1 +89 -144
  84. ansible/executor/powershell/bootstrap_wrapper.ps1 +24 -9
  85. ansible/executor/powershell/coverage_wrapper.ps1 +82 -135
  86. ansible/executor/powershell/exec_wrapper.ps1 +462 -196
  87. ansible/executor/powershell/module_manifest.py +417 -265
  88. ansible/executor/powershell/module_wrapper.ps1 +169 -186
  89. ansible/executor/powershell/psrp_fetch_file.ps1 +41 -0
  90. ansible/executor/powershell/psrp_put_file.ps1 +122 -0
  91. ansible/executor/powershell/winrm_fetch_file.ps1 +46 -0
  92. ansible/executor/powershell/winrm_put_file.ps1 +36 -0
  93. ansible/executor/process/worker.py +161 -96
  94. ansible/executor/stats.py +5 -5
  95. ansible/executor/task_executor.py +268 -258
  96. ansible/executor/task_queue_manager.py +124 -90
  97. ansible/executor/task_result.py +183 -78
  98. ansible/galaxy/__init__.py +2 -2
  99. ansible/galaxy/api.py +22 -18
  100. ansible/galaxy/collection/__init__.py +1 -1
  101. ansible/galaxy/collection/concrete_artifact_manager.py +8 -11
  102. ansible/galaxy/dependency_resolution/dataclasses.py +14 -4
  103. ansible/galaxy/dependency_resolution/providers.py +1 -1
  104. ansible/galaxy/dependency_resolution/reporters.py +81 -0
  105. ansible/galaxy/role.py +4 -8
  106. ansible/galaxy/token.py +28 -21
  107. ansible/inventory/data.py +47 -57
  108. ansible/inventory/group.py +44 -72
  109. ansible/inventory/helpers.py +9 -0
  110. ansible/inventory/host.py +32 -54
  111. ansible/inventory/manager.py +78 -34
  112. ansible/keyword_desc.yml +1 -1
  113. ansible/module_utils/_internal/__init__.py +55 -0
  114. ansible/module_utils/_internal/_ambient_context.py +58 -0
  115. ansible/module_utils/_internal/_ansiballz.py +133 -0
  116. ansible/module_utils/_internal/_concurrent/_daemon_threading.py +1 -0
  117. ansible/module_utils/_internal/_dataclass_annotation_patch.py +64 -0
  118. ansible/module_utils/_internal/_dataclass_validation.py +217 -0
  119. ansible/module_utils/_internal/_datatag/__init__.py +928 -0
  120. ansible/module_utils/_internal/_datatag/_tags.py +38 -0
  121. ansible/module_utils/_internal/_debugging.py +31 -0
  122. ansible/module_utils/_internal/_errors.py +30 -0
  123. ansible/module_utils/_internal/_json/__init__.py +63 -0
  124. ansible/module_utils/_internal/_json/_legacy_encoder.py +26 -0
  125. ansible/module_utils/_internal/_json/_profiles/__init__.py +410 -0
  126. ansible/module_utils/_internal/_json/_profiles/_fallback_to_str.py +73 -0
  127. ansible/module_utils/_internal/_json/_profiles/_module_legacy_c2m.py +31 -0
  128. ansible/module_utils/_internal/_json/_profiles/_module_legacy_m2c.py +35 -0
  129. ansible/module_utils/_internal/_json/_profiles/_module_modern_c2m.py +35 -0
  130. ansible/module_utils/_internal/_json/_profiles/_module_modern_m2c.py +33 -0
  131. ansible/module_utils/_internal/_json/_profiles/_tagless.py +50 -0
  132. ansible/module_utils/_internal/_patches/__init__.py +66 -0
  133. ansible/module_utils/_internal/_patches/_dataclass_annotation_patch.py +55 -0
  134. ansible/module_utils/_internal/_patches/_socket_patch.py +34 -0
  135. ansible/module_utils/_internal/_patches/_sys_intern_patch.py +34 -0
  136. ansible/module_utils/_internal/_plugin_exec_context.py +49 -0
  137. ansible/module_utils/_internal/_testing.py +0 -0
  138. ansible/module_utils/_internal/_traceback.py +89 -0
  139. ansible/module_utils/ansible_release.py +2 -2
  140. ansible/module_utils/api.py +1 -2
  141. ansible/module_utils/basic.py +152 -120
  142. ansible/module_utils/common/_utils.py +24 -28
  143. ansible/module_utils/common/collections.py +1 -2
  144. ansible/module_utils/common/dict_transformations.py +2 -2
  145. ansible/module_utils/common/file.py +2 -2
  146. ansible/module_utils/common/json.py +90 -84
  147. ansible/module_utils/common/locale.py +2 -2
  148. ansible/module_utils/common/messages.py +108 -0
  149. ansible/module_utils/common/parameters.py +27 -24
  150. ansible/module_utils/common/process.py +2 -2
  151. ansible/module_utils/common/respawn.py +41 -19
  152. ansible/module_utils/common/sentinel.py +66 -0
  153. ansible/module_utils/common/sys_info.py +8 -8
  154. ansible/module_utils/common/text/converters.py +16 -37
  155. ansible/module_utils/common/validation.py +35 -24
  156. ansible/module_utils/common/warnings.py +86 -25
  157. ansible/module_utils/common/yaml.py +29 -3
  158. ansible/module_utils/compat/datetime.py +33 -21
  159. ansible/module_utils/compat/paramiko.py +21 -10
  160. ansible/module_utils/compat/typing.py +6 -5
  161. ansible/module_utils/connection.py +2 -2
  162. ansible/module_utils/csharp/Ansible.Basic.cs +14 -11
  163. ansible/module_utils/csharp/Ansible.Become.cs +1 -0
  164. ansible/module_utils/csharp/Ansible._Async.cs +517 -0
  165. ansible/module_utils/datatag.py +46 -0
  166. ansible/module_utils/distro/__init__.py +2 -2
  167. ansible/module_utils/facts/ansible_collector.py +4 -5
  168. ansible/module_utils/facts/collector.py +13 -14
  169. ansible/module_utils/facts/compat.py +4 -4
  170. ansible/module_utils/facts/default_collectors.py +1 -1
  171. ansible/module_utils/facts/hardware/aix.py +34 -0
  172. ansible/module_utils/facts/hardware/base.py +1 -1
  173. ansible/module_utils/facts/hardware/darwin.py +1 -3
  174. ansible/module_utils/facts/hardware/freebsd.py +2 -2
  175. ansible/module_utils/facts/hardware/linux.py +4 -4
  176. ansible/module_utils/facts/namespace.py +1 -1
  177. ansible/module_utils/facts/network/base.py +1 -1
  178. ansible/module_utils/facts/network/fc_wwn.py +1 -2
  179. ansible/module_utils/facts/network/iscsi.py +1 -2
  180. ansible/module_utils/facts/network/nvme.py +1 -2
  181. ansible/module_utils/facts/other/facter.py +1 -2
  182. ansible/module_utils/facts/other/ohai.py +2 -3
  183. ansible/module_utils/facts/system/apparmor.py +1 -2
  184. ansible/module_utils/facts/system/caps.py +1 -1
  185. ansible/module_utils/facts/system/chroot.py +1 -2
  186. ansible/module_utils/facts/system/cmdline.py +1 -2
  187. ansible/module_utils/facts/system/date_time.py +5 -3
  188. ansible/module_utils/facts/system/distribution.py +9 -8
  189. ansible/module_utils/facts/system/dns.py +1 -1
  190. ansible/module_utils/facts/system/env.py +1 -2
  191. ansible/module_utils/facts/system/fips.py +7 -20
  192. ansible/module_utils/facts/system/loadavg.py +1 -2
  193. ansible/module_utils/facts/system/local.py +1 -2
  194. ansible/module_utils/facts/system/lsb.py +1 -2
  195. ansible/module_utils/facts/system/pkg_mgr.py +1 -2
  196. ansible/module_utils/facts/system/platform.py +1 -2
  197. ansible/module_utils/facts/system/python.py +1 -2
  198. ansible/module_utils/facts/system/selinux.py +1 -1
  199. ansible/module_utils/facts/system/service_mgr.py +1 -2
  200. ansible/module_utils/facts/system/ssh_pub_keys.py +1 -1
  201. ansible/module_utils/facts/system/systemd.py +1 -1
  202. ansible/module_utils/facts/system/user.py +1 -2
  203. ansible/module_utils/facts/utils.py +3 -3
  204. ansible/module_utils/facts/virtual/base.py +1 -1
  205. ansible/module_utils/facts/virtual/sunos.py +3 -15
  206. ansible/module_utils/facts/virtual/sysctl.py +3 -16
  207. ansible/module_utils/json_utils.py +2 -2
  208. ansible/module_utils/parsing/convert_bool.py +1 -1
  209. ansible/module_utils/service.py +18 -21
  210. ansible/module_utils/splitter.py +7 -7
  211. ansible/module_utils/testing.py +31 -0
  212. ansible/module_utils/urls.py +60 -31
  213. ansible/modules/add_host.py +4 -4
  214. ansible/modules/apt.py +60 -46
  215. ansible/modules/apt_key.py +19 -12
  216. ansible/modules/apt_repository.py +19 -16
  217. ansible/modules/assemble.py +6 -6
  218. ansible/modules/assert.py +4 -4
  219. ansible/modules/async_status.py +10 -12
  220. ansible/modules/async_wrapper.py +8 -3
  221. ansible/modules/blockinfile.py +6 -7
  222. ansible/modules/command.py +10 -17
  223. ansible/modules/copy.py +57 -144
  224. ansible/modules/cron.py +20 -15
  225. ansible/modules/deb822_repository.py +8 -9
  226. ansible/modules/debconf.py +5 -5
  227. ansible/modules/debug.py +4 -4
  228. ansible/modules/dnf.py +8 -8
  229. ansible/modules/dnf5.py +39 -13
  230. ansible/modules/dpkg_selections.py +4 -4
  231. ansible/modules/expect.py +8 -10
  232. ansible/modules/fail.py +4 -4
  233. ansible/modules/fetch.py +4 -4
  234. ansible/modules/file.py +174 -133
  235. ansible/modules/find.py +19 -17
  236. ansible/modules/gather_facts.py +3 -3
  237. ansible/modules/get_url.py +59 -53
  238. ansible/modules/getent.py +7 -9
  239. ansible/modules/git.py +28 -25
  240. ansible/modules/group.py +6 -6
  241. ansible/modules/group_by.py +4 -4
  242. ansible/modules/hostname.py +13 -29
  243. ansible/modules/import_playbook.py +6 -6
  244. ansible/modules/import_role.py +6 -6
  245. ansible/modules/import_tasks.py +6 -6
  246. ansible/modules/include_role.py +6 -6
  247. ansible/modules/include_tasks.py +6 -6
  248. ansible/modules/include_vars.py +6 -6
  249. ansible/modules/iptables.py +86 -73
  250. ansible/modules/known_hosts.py +10 -10
  251. ansible/modules/lineinfile.py +5 -5
  252. ansible/modules/meta.py +4 -4
  253. ansible/modules/mount_facts.py +2 -2
  254. ansible/modules/package.py +4 -4
  255. ansible/modules/package_facts.py +22 -10
  256. ansible/modules/pause.py +6 -6
  257. ansible/modules/ping.py +6 -6
  258. ansible/modules/pip.py +10 -11
  259. ansible/modules/raw.py +4 -4
  260. ansible/modules/reboot.py +6 -6
  261. ansible/modules/replace.py +9 -13
  262. ansible/modules/rpm_key.py +7 -8
  263. ansible/modules/script.py +4 -4
  264. ansible/modules/service.py +7 -8
  265. ansible/modules/service_facts.py +87 -10
  266. ansible/modules/set_fact.py +5 -5
  267. ansible/modules/set_stats.py +4 -4
  268. ansible/modules/setup.py +2 -2
  269. ansible/modules/shell.py +6 -6
  270. ansible/modules/slurp.py +6 -6
  271. ansible/modules/stat.py +9 -23
  272. ansible/modules/subversion.py +15 -15
  273. ansible/modules/systemd.py +6 -6
  274. ansible/modules/systemd_service.py +6 -6
  275. ansible/modules/sysvinit.py +6 -6
  276. ansible/modules/tempfile.py +5 -6
  277. ansible/modules/template.py +6 -6
  278. ansible/modules/unarchive.py +32 -11
  279. ansible/modules/uri.py +33 -26
  280. ansible/modules/user.py +53 -34
  281. ansible/modules/validate_argument_spec.py +10 -7
  282. ansible/modules/wait_for.py +32 -27
  283. ansible/modules/wait_for_connection.py +6 -6
  284. ansible/modules/yum_repository.py +6 -6
  285. ansible/parsing/ajson.py +14 -32
  286. ansible/parsing/dataloader.py +99 -54
  287. ansible/parsing/mod_args.py +28 -44
  288. ansible/parsing/plugin_docs.py +21 -86
  289. ansible/parsing/quoting.py +1 -1
  290. ansible/parsing/splitter.py +27 -12
  291. ansible/parsing/utils/addresses.py +24 -24
  292. ansible/parsing/utils/jsonify.py +5 -1
  293. ansible/parsing/utils/yaml.py +32 -61
  294. ansible/parsing/vault/__init__.py +319 -87
  295. ansible/parsing/yaml/__init__.py +0 -18
  296. ansible/parsing/yaml/dumper.py +6 -120
  297. ansible/parsing/yaml/loader.py +6 -39
  298. ansible/parsing/yaml/objects.py +43 -335
  299. ansible/playbook/__init__.py +1 -1
  300. ansible/playbook/attribute.py +8 -3
  301. ansible/playbook/base.py +182 -132
  302. ansible/playbook/block.py +26 -24
  303. ansible/playbook/collectionsearch.py +1 -15
  304. ansible/playbook/conditional.py +3 -77
  305. ansible/playbook/handler.py +8 -2
  306. ansible/playbook/helpers.py +41 -53
  307. ansible/playbook/included_file.py +31 -27
  308. ansible/playbook/loop_control.py +2 -2
  309. ansible/playbook/play.py +85 -44
  310. ansible/playbook/play_context.py +12 -17
  311. ansible/playbook/playbook_include.py +14 -15
  312. ansible/playbook/role/__init__.py +24 -26
  313. ansible/playbook/role/definition.py +15 -17
  314. ansible/playbook/role/include.py +2 -4
  315. ansible/playbook/role/metadata.py +10 -11
  316. ansible/playbook/role_include.py +3 -3
  317. ansible/playbook/taggable.py +13 -8
  318. ansible/playbook/task.py +188 -118
  319. ansible/playbook/task_include.py +5 -5
  320. ansible/plugins/__init__.py +68 -21
  321. ansible/plugins/action/__init__.py +209 -176
  322. ansible/plugins/action/add_host.py +1 -1
  323. ansible/plugins/action/assemble.py +1 -1
  324. ansible/plugins/action/assert.py +54 -66
  325. ansible/plugins/action/copy.py +7 -11
  326. ansible/plugins/action/debug.py +37 -31
  327. ansible/plugins/action/dnf.py +3 -4
  328. ansible/plugins/action/fail.py +1 -1
  329. ansible/plugins/action/fetch.py +4 -5
  330. ansible/plugins/action/gather_facts.py +7 -6
  331. ansible/plugins/action/group_by.py +1 -1
  332. ansible/plugins/action/include_vars.py +10 -11
  333. ansible/plugins/action/package.py +3 -6
  334. ansible/plugins/action/pause.py +2 -2
  335. ansible/plugins/action/script.py +15 -8
  336. ansible/plugins/action/service.py +6 -11
  337. ansible/plugins/action/set_fact.py +3 -12
  338. ansible/plugins/action/set_stats.py +3 -8
  339. ansible/plugins/action/template.py +35 -59
  340. ansible/plugins/action/unarchive.py +1 -1
  341. ansible/plugins/action/validate_argument_spec.py +5 -5
  342. ansible/plugins/action/wait_for_connection.py +1 -1
  343. ansible/plugins/become/__init__.py +31 -8
  344. ansible/plugins/become/runas.py +71 -0
  345. ansible/plugins/become/su.py +13 -8
  346. ansible/plugins/become/sudo.py +19 -0
  347. ansible/plugins/cache/__init__.py +35 -44
  348. ansible/plugins/cache/base.py +8 -0
  349. ansible/plugins/cache/jsonfile.py +10 -16
  350. ansible/plugins/cache/memory.py +6 -12
  351. ansible/plugins/callback/__init__.py +284 -179
  352. ansible/plugins/callback/default.py +99 -92
  353. ansible/plugins/callback/junit.py +44 -39
  354. ansible/plugins/callback/minimal.py +28 -25
  355. ansible/plugins/callback/oneline.py +28 -21
  356. ansible/plugins/callback/tree.py +16 -11
  357. ansible/plugins/connection/__init__.py +47 -34
  358. ansible/plugins/connection/local.py +150 -54
  359. ansible/plugins/connection/paramiko_ssh.py +21 -18
  360. ansible/plugins/connection/psrp.py +76 -165
  361. ansible/plugins/connection/ssh.py +301 -78
  362. ansible/plugins/connection/winrm.py +58 -140
  363. ansible/plugins/doc_fragments/action_common_attributes.py +14 -14
  364. ansible/plugins/doc_fragments/action_core.py +6 -6
  365. ansible/plugins/doc_fragments/backup.py +2 -2
  366. ansible/plugins/doc_fragments/checksum_common.py +27 -0
  367. ansible/plugins/doc_fragments/constructed.py +6 -2
  368. ansible/plugins/doc_fragments/decrypt.py +2 -2
  369. ansible/plugins/doc_fragments/default_callback.py +2 -2
  370. ansible/plugins/doc_fragments/files.py +2 -2
  371. ansible/plugins/doc_fragments/inventory_cache.py +2 -2
  372. ansible/plugins/doc_fragments/result_format_callback.py +2 -2
  373. ansible/plugins/doc_fragments/return_common.py +2 -2
  374. ansible/plugins/doc_fragments/template_common.py +4 -4
  375. ansible/plugins/doc_fragments/url.py +17 -1
  376. ansible/plugins/doc_fragments/url_windows.py +2 -2
  377. ansible/plugins/doc_fragments/validate.py +2 -2
  378. ansible/plugins/doc_fragments/vars_plugin_staging.py +2 -2
  379. ansible/plugins/filter/__init__.py +6 -2
  380. ansible/plugins/filter/b64decode.yml +22 -0
  381. ansible/plugins/filter/b64encode.yml +22 -0
  382. ansible/plugins/filter/bool.yml +11 -4
  383. ansible/plugins/filter/core.py +225 -108
  384. ansible/plugins/filter/encryption.py +32 -32
  385. ansible/plugins/filter/flatten.yml +3 -2
  386. ansible/plugins/filter/human_to_bytes.yml +1 -1
  387. ansible/plugins/filter/mathstuff.py +30 -37
  388. ansible/plugins/filter/password_hash.yml +8 -0
  389. ansible/plugins/filter/regex_search.yml +1 -4
  390. ansible/plugins/filter/split.yml +1 -1
  391. ansible/plugins/filter/to_nice_yaml.yml +0 -4
  392. ansible/plugins/filter/to_yaml.yml +0 -4
  393. ansible/plugins/filter/unvault.yml +1 -1
  394. ansible/plugins/filter/urls.py +1 -1
  395. ansible/plugins/filter/urlsplit.py +8 -9
  396. ansible/plugins/filter/vault.yml +14 -9
  397. ansible/plugins/filter/win_basename.yml +6 -1
  398. ansible/plugins/filter/win_dirname.yml +5 -0
  399. ansible/plugins/inventory/__init__.py +97 -77
  400. ansible/plugins/inventory/advanced_host_list.py +7 -5
  401. ansible/plugins/inventory/auto.py +11 -4
  402. ansible/plugins/inventory/constructed.py +21 -24
  403. ansible/plugins/inventory/generator.py +16 -11
  404. ansible/plugins/inventory/host_list.py +7 -5
  405. ansible/plugins/inventory/ini.py +78 -44
  406. ansible/plugins/inventory/script.py +189 -119
  407. ansible/plugins/inventory/toml.py +16 -126
  408. ansible/plugins/inventory/yaml.py +10 -8
  409. ansible/plugins/list.py +3 -3
  410. ansible/plugins/loader.py +197 -82
  411. ansible/plugins/lookup/__init__.py +21 -4
  412. ansible/plugins/lookup/config.py +21 -35
  413. ansible/plugins/lookup/csvfile.py +3 -2
  414. ansible/plugins/lookup/dict.py +1 -6
  415. ansible/plugins/lookup/env.py +12 -9
  416. ansible/plugins/lookup/file.py +5 -8
  417. ansible/plugins/lookup/first_found.py +86 -55
  418. ansible/plugins/lookup/indexed_items.py +1 -10
  419. ansible/plugins/lookup/ini.py +14 -13
  420. ansible/plugins/lookup/items.py +1 -1
  421. ansible/plugins/lookup/lines.py +8 -1
  422. ansible/plugins/lookup/list.py +1 -1
  423. ansible/plugins/lookup/nested.py +2 -18
  424. ansible/plugins/lookup/password.py +5 -5
  425. ansible/plugins/lookup/pipe.py +5 -7
  426. ansible/plugins/lookup/sequence.py +18 -8
  427. ansible/plugins/lookup/subelements.py +1 -4
  428. ansible/plugins/lookup/template.py +42 -36
  429. ansible/plugins/lookup/together.py +0 -12
  430. ansible/plugins/lookup/unvault.py +1 -5
  431. ansible/plugins/lookup/url.py +2 -8
  432. ansible/plugins/lookup/vars.py +16 -24
  433. ansible/plugins/shell/__init__.py +2 -2
  434. ansible/plugins/shell/cmd.py +2 -2
  435. ansible/plugins/shell/powershell.py +39 -22
  436. ansible/plugins/shell/sh.py +3 -2
  437. ansible/plugins/strategy/__init__.py +159 -184
  438. ansible/plugins/strategy/debug.py +2 -2
  439. ansible/plugins/strategy/free.py +16 -31
  440. ansible/plugins/strategy/host_pinned.py +2 -2
  441. ansible/plugins/strategy/linear.py +41 -41
  442. ansible/plugins/terminal/__init__.py +4 -4
  443. ansible/plugins/test/__init__.py +7 -2
  444. ansible/plugins/test/core.py +55 -21
  445. ansible/plugins/test/files.py +1 -1
  446. ansible/plugins/test/mathstuff.py +3 -3
  447. ansible/plugins/test/uri.py +3 -3
  448. ansible/plugins/vars/host_group_vars.py +7 -14
  449. ansible/release.py +2 -2
  450. ansible/template/__init__.py +370 -944
  451. ansible/utils/__init__.py +0 -18
  452. ansible/utils/_ssh_agent.py +657 -0
  453. ansible/utils/collection_loader/__init__.py +52 -5
  454. ansible/utils/collection_loader/_collection_config.py +5 -6
  455. ansible/utils/collection_loader/_collection_finder.py +79 -93
  456. ansible/utils/collection_loader/_collection_meta.py +13 -8
  457. ansible/utils/display.py +433 -63
  458. ansible/utils/encrypt.py +27 -19
  459. ansible/utils/fqcn.py +2 -2
  460. ansible/utils/hashing.py +2 -2
  461. ansible/utils/helpers.py +2 -2
  462. ansible/utils/listify.py +8 -8
  463. ansible/utils/lock.py +2 -2
  464. ansible/utils/path.py +4 -4
  465. ansible/utils/plugin_docs.py +14 -13
  466. ansible/utils/sentinel.py +4 -62
  467. ansible/utils/singleton.py +2 -0
  468. ansible/utils/ssh_functions.py +1 -1
  469. ansible/utils/unsafe_proxy.py +23 -332
  470. ansible/utils/vars.py +51 -8
  471. ansible/utils/version.py +2 -2
  472. ansible/vars/clean.py +5 -5
  473. ansible/vars/hostvars.py +60 -90
  474. ansible/vars/manager.py +206 -282
  475. ansible/vars/reserved.py +8 -9
  476. ansible_core-2.19.0b2.dist-info/BSD-3-Clause.txt +28 -0
  477. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/METADATA +5 -4
  478. ansible_core-2.19.0b2.dist-info/RECORD +1072 -0
  479. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/WHEEL +1 -1
  480. ansible_test/_data/completion/docker.txt +7 -7
  481. ansible_test/_data/completion/remote.txt +6 -6
  482. ansible_test/_data/completion/windows.txt +1 -0
  483. ansible_test/_data/requirements/ansible.txt +2 -2
  484. ansible_test/_data/requirements/sanity.ansible-doc.txt +3 -3
  485. ansible_test/_data/requirements/sanity.changelog.txt +1 -1
  486. ansible_test/_data/requirements/sanity.import.plugin.txt +2 -2
  487. ansible_test/_data/requirements/sanity.pylint.txt +4 -4
  488. ansible_test/_data/requirements/sanity.validate-modules.txt +2 -2
  489. ansible_test/_data/requirements/sanity.yamllint.txt +1 -1
  490. ansible_test/_data/requirements/units.txt +1 -0
  491. ansible_test/_internal/__init__.py +1 -0
  492. ansible_test/_internal/ansible_util.py +2 -0
  493. ansible_test/_internal/become.py +1 -0
  494. ansible_test/_internal/bootstrap.py +1 -0
  495. ansible_test/_internal/cache.py +1 -0
  496. ansible_test/_internal/cgroup.py +1 -0
  497. ansible_test/_internal/ci/__init__.py +1 -0
  498. ansible_test/_internal/ci/azp.py +1 -0
  499. ansible_test/_internal/ci/local.py +1 -0
  500. ansible_test/_internal/classification/__init__.py +1 -0
  501. ansible_test/_internal/classification/common.py +1 -0
  502. ansible_test/_internal/classification/csharp.py +1 -0
  503. ansible_test/_internal/classification/powershell.py +1 -0
  504. ansible_test/_internal/classification/python.py +1 -0
  505. ansible_test/_internal/cli/__init__.py +1 -0
  506. ansible_test/_internal/cli/actions.py +1 -0
  507. ansible_test/_internal/cli/argparsing/__init__.py +1 -0
  508. ansible_test/_internal/cli/argparsing/actions.py +1 -0
  509. ansible_test/_internal/cli/argparsing/argcompletion.py +1 -0
  510. ansible_test/_internal/cli/argparsing/parsers.py +1 -0
  511. ansible_test/_internal/cli/commands/__init__.py +11 -0
  512. ansible_test/_internal/cli/commands/coverage/__init__.py +1 -0
  513. ansible_test/_internal/cli/commands/coverage/analyze/__init__.py +1 -0
  514. ansible_test/_internal/cli/commands/coverage/analyze/targets/__init__.py +1 -0
  515. ansible_test/_internal/cli/commands/coverage/analyze/targets/combine.py +1 -0
  516. ansible_test/_internal/cli/commands/coverage/analyze/targets/expand.py +1 -0
  517. ansible_test/_internal/cli/commands/coverage/analyze/targets/filter.py +1 -0
  518. ansible_test/_internal/cli/commands/coverage/analyze/targets/generate.py +1 -0
  519. ansible_test/_internal/cli/commands/coverage/analyze/targets/missing.py +1 -0
  520. ansible_test/_internal/cli/commands/coverage/combine.py +1 -0
  521. ansible_test/_internal/cli/commands/coverage/erase.py +1 -0
  522. ansible_test/_internal/cli/commands/coverage/html.py +1 -0
  523. ansible_test/_internal/cli/commands/coverage/report.py +1 -0
  524. ansible_test/_internal/cli/commands/coverage/xml.py +1 -0
  525. ansible_test/_internal/cli/commands/env.py +1 -0
  526. ansible_test/_internal/cli/commands/integration/__init__.py +1 -0
  527. ansible_test/_internal/cli/commands/integration/network.py +1 -0
  528. ansible_test/_internal/cli/commands/integration/posix.py +1 -0
  529. ansible_test/_internal/cli/commands/integration/windows.py +1 -0
  530. ansible_test/_internal/cli/commands/sanity.py +9 -0
  531. ansible_test/_internal/cli/commands/shell.py +1 -0
  532. ansible_test/_internal/cli/commands/units.py +1 -0
  533. ansible_test/_internal/cli/compat.py +1 -0
  534. ansible_test/_internal/cli/completers.py +1 -0
  535. ansible_test/_internal/cli/converters.py +1 -0
  536. ansible_test/_internal/cli/environments.py +1 -0
  537. ansible_test/_internal/cli/epilog.py +1 -0
  538. ansible_test/_internal/cli/parsers/__init__.py +1 -0
  539. ansible_test/_internal/cli/parsers/base_argument_parsers.py +1 -0
  540. ansible_test/_internal/cli/parsers/helpers.py +1 -0
  541. ansible_test/_internal/cli/parsers/host_config_parsers.py +1 -0
  542. ansible_test/_internal/cli/parsers/key_value_parsers.py +1 -0
  543. ansible_test/_internal/cli/parsers/value_parsers.py +1 -0
  544. ansible_test/_internal/commands/__init__.py +1 -0
  545. ansible_test/_internal/commands/coverage/__init__.py +2 -1
  546. ansible_test/_internal/commands/coverage/analyze/__init__.py +1 -0
  547. ansible_test/_internal/commands/coverage/analyze/targets/__init__.py +1 -0
  548. ansible_test/_internal/commands/coverage/analyze/targets/combine.py +1 -0
  549. ansible_test/_internal/commands/coverage/analyze/targets/expand.py +1 -0
  550. ansible_test/_internal/commands/coverage/analyze/targets/filter.py +1 -0
  551. ansible_test/_internal/commands/coverage/analyze/targets/generate.py +1 -0
  552. ansible_test/_internal/commands/coverage/analyze/targets/missing.py +1 -0
  553. ansible_test/_internal/commands/coverage/combine.py +2 -1
  554. ansible_test/_internal/commands/coverage/erase.py +1 -0
  555. ansible_test/_internal/commands/coverage/html.py +1 -0
  556. ansible_test/_internal/commands/coverage/report.py +1 -0
  557. ansible_test/_internal/commands/coverage/xml.py +1 -0
  558. ansible_test/_internal/commands/env/__init__.py +2 -0
  559. ansible_test/_internal/commands/integration/__init__.py +4 -0
  560. ansible_test/_internal/commands/integration/cloud/__init__.py +1 -0
  561. ansible_test/_internal/commands/integration/cloud/acme.py +2 -1
  562. ansible_test/_internal/commands/integration/cloud/aws.py +1 -0
  563. ansible_test/_internal/commands/integration/cloud/azure.py +1 -0
  564. ansible_test/_internal/commands/integration/cloud/cs.py +1 -0
  565. ansible_test/_internal/commands/integration/cloud/digitalocean.py +1 -0
  566. ansible_test/_internal/commands/integration/cloud/galaxy.py +3 -2
  567. ansible_test/_internal/commands/integration/cloud/hcloud.py +1 -0
  568. ansible_test/_internal/commands/integration/cloud/httptester.py +2 -1
  569. ansible_test/_internal/commands/integration/cloud/nios.py +2 -1
  570. ansible_test/_internal/commands/integration/cloud/opennebula.py +1 -0
  571. ansible_test/_internal/commands/integration/cloud/openshift.py +1 -0
  572. ansible_test/_internal/commands/integration/cloud/scaleway.py +1 -0
  573. ansible_test/_internal/commands/integration/cloud/vcenter.py +1 -0
  574. ansible_test/_internal/commands/integration/cloud/vultr.py +1 -0
  575. ansible_test/_internal/commands/integration/coverage.py +1 -0
  576. ansible_test/_internal/commands/integration/filters.py +1 -0
  577. ansible_test/_internal/commands/integration/network.py +1 -0
  578. ansible_test/_internal/commands/integration/posix.py +1 -0
  579. ansible_test/_internal/commands/integration/windows.py +1 -0
  580. ansible_test/_internal/commands/sanity/__init__.py +16 -1
  581. ansible_test/_internal/commands/sanity/ansible_doc.py +1 -0
  582. ansible_test/_internal/commands/sanity/bin_symlinks.py +1 -0
  583. ansible_test/_internal/commands/sanity/compile.py +1 -0
  584. ansible_test/_internal/commands/sanity/ignores.py +1 -0
  585. ansible_test/_internal/commands/sanity/import.py +1 -0
  586. ansible_test/_internal/commands/sanity/integration_aliases.py +1 -0
  587. ansible_test/_internal/commands/sanity/pep8.py +1 -0
  588. ansible_test/_internal/commands/sanity/pslint.py +1 -0
  589. ansible_test/_internal/commands/sanity/pylint.py +24 -26
  590. ansible_test/_internal/commands/sanity/shellcheck.py +1 -0
  591. ansible_test/_internal/commands/sanity/validate_modules.py +1 -0
  592. ansible_test/_internal/commands/sanity/yamllint.py +1 -0
  593. ansible_test/_internal/commands/shell/__init__.py +1 -0
  594. ansible_test/_internal/commands/units/__init__.py +1 -0
  595. ansible_test/_internal/compat/__init__.py +1 -0
  596. ansible_test/_internal/compat/packaging.py +1 -0
  597. ansible_test/_internal/compat/yaml.py +1 -0
  598. ansible_test/_internal/completion.py +1 -0
  599. ansible_test/_internal/config.py +2 -0
  600. ansible_test/_internal/connections.py +1 -0
  601. ansible_test/_internal/constants.py +1 -0
  602. ansible_test/_internal/containers.py +1 -0
  603. ansible_test/_internal/content_config.py +1 -0
  604. ansible_test/_internal/core_ci.py +1 -0
  605. ansible_test/_internal/coverage_util.py +11 -10
  606. ansible_test/_internal/data.py +1 -0
  607. ansible_test/_internal/delegation.py +1 -0
  608. ansible_test/_internal/dev/__init__.py +1 -0
  609. ansible_test/_internal/dev/container_probe.py +1 -0
  610. ansible_test/_internal/diff.py +3 -2
  611. ansible_test/_internal/docker_util.py +2 -1
  612. ansible_test/_internal/encoding.py +1 -0
  613. ansible_test/_internal/executor.py +1 -0
  614. ansible_test/_internal/git.py +1 -0
  615. ansible_test/_internal/host_configs.py +1 -0
  616. ansible_test/_internal/host_profiles.py +1 -0
  617. ansible_test/_internal/http.py +1 -0
  618. ansible_test/_internal/init.py +1 -0
  619. ansible_test/_internal/inventory.py +35 -3
  620. ansible_test/_internal/io.py +1 -0
  621. ansible_test/_internal/metadata.py +1 -0
  622. ansible_test/_internal/payload.py +1 -0
  623. ansible_test/_internal/provider/__init__.py +1 -0
  624. ansible_test/_internal/provider/layout/__init__.py +1 -0
  625. ansible_test/_internal/provider/layout/ansible.py +1 -0
  626. ansible_test/_internal/provider/layout/collection.py +1 -0
  627. ansible_test/_internal/provider/layout/unsupported.py +1 -0
  628. ansible_test/_internal/provider/source/__init__.py +1 -0
  629. ansible_test/_internal/provider/source/git.py +1 -0
  630. ansible_test/_internal/provider/source/installed.py +1 -0
  631. ansible_test/_internal/provider/source/unsupported.py +1 -0
  632. ansible_test/_internal/provider/source/unversioned.py +1 -0
  633. ansible_test/_internal/provisioning.py +1 -0
  634. ansible_test/_internal/pypi_proxy.py +6 -5
  635. ansible_test/_internal/python_requirements.py +1 -0
  636. ansible_test/_internal/ssh.py +1 -0
  637. ansible_test/_internal/target.py +1 -0
  638. ansible_test/_internal/test.py +3 -2
  639. ansible_test/_internal/thread.py +1 -0
  640. ansible_test/_internal/timeout.py +1 -0
  641. ansible_test/_internal/util.py +1 -0
  642. ansible_test/_internal/util_common.py +5 -2
  643. ansible_test/_internal/venv.py +1 -0
  644. ansible_test/_util/controller/sanity/code-smell/action-plugin-docs.py +1 -0
  645. ansible_test/_util/controller/sanity/code-smell/changelog/sphinx.py +1 -0
  646. ansible_test/_util/controller/sanity/code-smell/changelog.py +1 -0
  647. ansible_test/_util/controller/sanity/code-smell/empty-init.py +1 -0
  648. ansible_test/_util/controller/sanity/code-smell/line-endings.py +1 -0
  649. ansible_test/_util/controller/sanity/code-smell/no-assert.py +1 -0
  650. ansible_test/_util/controller/sanity/code-smell/no-get-exception.py +1 -0
  651. ansible_test/_util/controller/sanity/code-smell/no-illegal-filenames.py +1 -0
  652. ansible_test/_util/controller/sanity/code-smell/no-smart-quotes.py +1 -0
  653. ansible_test/_util/controller/sanity/code-smell/replace-urlopen.py +1 -0
  654. ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py +28 -1
  655. ansible_test/_util/controller/sanity/code-smell/shebang.py +1 -0
  656. ansible_test/_util/controller/sanity/code-smell/symlinks.py +1 -0
  657. ansible_test/_util/controller/sanity/code-smell/use-argspec-type-path.py +1 -0
  658. ansible_test/_util/controller/sanity/code-smell/use-compat-six.py +1 -0
  659. ansible_test/_util/controller/sanity/integration-aliases/yaml_to_json.py +2 -1
  660. ansible_test/_util/controller/sanity/pep8/current-ignore.txt +4 -0
  661. ansible_test/_util/controller/sanity/pylint/config/ansible-test-target.cfg +7 -5
  662. ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg +7 -5
  663. ansible_test/_util/controller/sanity/pylint/config/code-smell.cfg +7 -5
  664. ansible_test/_util/controller/sanity/pylint/config/collection.cfg +3 -5
  665. ansible_test/_util/controller/sanity/pylint/config/default.cfg +7 -7
  666. ansible_test/_util/controller/sanity/pylint/plugins/deprecated.py +1 -13
  667. ansible_test/_util/controller/sanity/pylint/plugins/hide_unraisable.py +1 -0
  668. ansible_test/_util/controller/sanity/pylint/plugins/string_format.py +1 -8
  669. ansible_test/_util/controller/sanity/pylint/plugins/unwanted.py +1 -8
  670. ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +55 -28
  671. ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py +12 -5
  672. ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +13 -2
  673. ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py +1 -0
  674. ansible_test/_util/controller/sanity/yamllint/yamllinter.py +35 -17
  675. ansible_test/_util/controller/tools/collection_detail.py +1 -0
  676. ansible_test/_util/controller/tools/yaml_to_json.py +2 -1
  677. ansible_test/_util/target/pytest/plugins/ansible_forked.py +6 -1
  678. ansible_test/_util/target/pytest/plugins/ansible_pytest_collections.py +2 -1
  679. ansible_test/_util/target/pytest/plugins/ansible_pytest_coverage.py +1 -0
  680. ansible_test/_util/target/sanity/compile/compile.py +1 -0
  681. ansible_test/_util/target/sanity/import/importer.py +15 -16
  682. ansible_test/_util/target/setup/bootstrap.sh +9 -20
  683. ansible_test/_util/target/setup/probe_cgroups.py +1 -0
  684. ansible_test/_util/target/setup/quiet_pip.py +1 -0
  685. ansible_test/_util/target/setup/requirements.py +35 -27
  686. ansible_test/_util/target/tools/virtualenvcheck.py +2 -1
  687. ansible_test/_util/target/tools/yamlcheck.py +2 -1
  688. ansible/compat/selectors.py +0 -32
  689. ansible/errors/yaml_strings.py +0 -138
  690. ansible/executor/action_write_locks.py +0 -44
  691. ansible/executor/discovery/python_target.py +0 -47
  692. ansible/executor/powershell/module_powershell_wrapper.ps1 +0 -86
  693. ansible/executor/powershell/module_script_wrapper.ps1 +0 -22
  694. ansible/module_utils/compat/importlib.py +0 -26
  695. ansible/module_utils/compat/selectors.py +0 -32
  696. ansible/module_utils/pycompat24.py +0 -73
  697. ansible/parsing/yaml/constructor.py +0 -178
  698. ansible/template/native_helpers.py +0 -251
  699. ansible/template/template.py +0 -43
  700. ansible/template/vars.py +0 -77
  701. ansible/utils/native_jinja.py +0 -11
  702. ansible/vars/fact_cache.py +0 -71
  703. ansible_core-2.18.5rc1.dist-info/RECORD +0 -992
  704. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/Apache-License.txt +0 -0
  705. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/COPYING +0 -0
  706. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/MIT-license.txt +0 -0
  707. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/PSF-license.txt +0 -0
  708. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/entry_points.txt +0 -0
  709. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/simplified_bsd.txt +0 -0
  710. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/top_level.txt +0 -0
@@ -1,174 +1,225 @@
1
- # (c) 2018 Ansible Project
1
+ # (c) 2025 Ansible Project
2
2
  # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
3
3
 
4
- param(
5
- [Parameter(Mandatory = $true)][System.Collections.IDictionary]$Payload
6
- )
7
-
8
- $ErrorActionPreference = "Stop"
4
+ #AnsibleRequires -CSharpUtil Ansible._Async
9
5
 
10
- Write-AnsibleLog "INFO - starting async_wrapper" "async_wrapper"
6
+ using namespace System.Collections
7
+ using namespace System.Diagnostics
8
+ using namespace System.IO
9
+ using namespace System.IO.Pipes
10
+ using namespace System.Text
11
+ using namespace System.Threading
11
12
 
12
- if (-not $Payload.environment.ContainsKey("ANSIBLE_ASYNC_DIR")) {
13
- Write-AnsibleError -Message "internal error: the environment variable ANSIBLE_ASYNC_DIR is not set and is required for an async task"
14
- $host.SetShouldExit(1)
15
- return
16
- }
17
- $async_dir = [System.Environment]::ExpandEnvironmentVariables($Payload.environment.ANSIBLE_ASYNC_DIR)
18
-
19
- # calculate the result path so we can include it in the worker payload
20
- $jid = $Payload.async_jid
21
- $local_jid = $jid + "." + $pid
22
-
23
- $results_path = [System.IO.Path]::Combine($async_dir, $local_jid)
24
-
25
- Write-AnsibleLog "INFO - creating async results path at '$results_path'" "async_wrapper"
26
-
27
- $Payload.async_results_path = $results_path
28
- [System.IO.Directory]::CreateDirectory([System.IO.Path]::GetDirectoryName($results_path)) > $null
29
-
30
- # we use Win32_Process to escape the current process job, CreateProcess with a
31
- # breakaway flag won't work for psrp as the psrp process does not have breakaway
32
- # rights. Unfortunately we can't read/write to the spawned process as we can't
33
- # inherit the handles. We use a locked down named pipe to send the exec_wrapper
34
- # payload. Anonymous pipes won't work as the spawned process will not be a child
35
- # of the current one and will not be able to inherit the handles
36
-
37
- # pop the async_wrapper action so we don't get stuck in a loop and create new
38
- # exec_wrapper for our async process
39
- $Payload.actions = $Payload.actions[1..99]
40
- $payload_json = ConvertTo-Json -InputObject $Payload -Depth 99 -Compress
41
-
42
- #
43
- $exec_wrapper = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Payload.exec_wrapper))
44
- $exec_wrapper += "`0`0`0`0" + $payload_json
45
- $payload_bytes = [System.Text.Encoding]::UTF8.GetBytes($exec_wrapper)
46
- $pipe_name = "ansible-async-$jid-$([guid]::NewGuid())"
47
-
48
- # template the async process command line with the payload details
49
- $bootstrap_wrapper = {
50
- # help with debugging errors as we loose visibility of the process output
51
- # from here on
52
- trap {
53
- $wrapper_path = "$($env:TEMP)\ansible-async-wrapper-error-$(Get-Date -Format "yyyy-MM-ddTHH-mm-ss.ffffZ").txt"
54
- $error_msg = "Error while running the async exec wrapper`r`n$($_ | Out-String)`r`n$($_.ScriptStackTrace)"
55
- Set-Content -Path $wrapper_path -Value $error_msg
56
- break
57
- }
13
+ [CmdletBinding()]
14
+ param (
15
+ [Parameter(Mandatory)]
16
+ [string]
17
+ $AsyncDir,
58
18
 
59
- &chcp.com 65001 > $null
60
-
61
- # store the pipe name and no. of bytes to read, these are populated before
62
- # before the process is created - do not remove or changed
63
- $pipe_name = ""
64
- $bytes_length = 0
65
-
66
- $input_bytes = New-Object -TypeName byte[] -ArgumentList $bytes_length
67
- $pipe = New-Object -TypeName System.IO.Pipes.NamedPipeClientStream -ArgumentList @(
68
- ".", # localhost
69
- $pipe_name,
70
- [System.IO.Pipes.PipeDirection]::In,
71
- [System.IO.Pipes.PipeOptions]::None,
72
- [System.Security.Principal.TokenImpersonationLevel]::Anonymous
73
- )
74
- try {
75
- $pipe.Connect()
76
- $pipe.Read($input_bytes, 0, $bytes_length) > $null
77
- }
78
- finally {
79
- $pipe.Close()
80
- }
81
- $exec = [System.Text.Encoding]::UTF8.GetString($input_bytes)
82
- $exec_parts = $exec.Split(@("`0`0`0`0"), 2, [StringSplitOptions]::RemoveEmptyEntries)
83
- Set-Variable -Name json_raw -Value $exec_parts[1]
84
- $exec = [ScriptBlock]::Create($exec_parts[0])
85
- &$exec
86
- }
19
+ [Parameter(Mandatory)]
20
+ [string]
21
+ $AsyncJid,
87
22
 
88
- $bootstrap_wrapper = $bootstrap_wrapper.ToString().Replace('$pipe_name = ""', "`$pipe_name = `"$pipe_name`"")
89
- $bootstrap_wrapper = $bootstrap_wrapper.Replace('$bytes_length = 0', "`$bytes_length = $($payload_bytes.Count)")
90
- $encoded_command = [System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($bootstrap_wrapper))
91
- $pwsh_path = "$env:SystemRoot\System32\WindowsPowerShell\v1.0\powershell.exe"
92
- $exec_args = "`"$pwsh_path`" -NonInteractive -NoProfile -ExecutionPolicy Bypass -EncodedCommand $encoded_command"
93
-
94
- # create a named pipe that is set to allow only the current user read access
95
- $current_user = ([Security.Principal.WindowsIdentity]::GetCurrent()).User
96
- $pipe_sec = New-Object -TypeName System.IO.Pipes.PipeSecurity
97
- $pipe_ar = New-Object -TypeName System.IO.Pipes.PipeAccessRule -ArgumentList @(
98
- $current_user,
99
- [System.IO.Pipes.PipeAccessRights]::Read,
100
- [System.Security.AccessControl.AccessControlType]::Allow
101
- )
102
- $pipe_sec.AddAccessRule($pipe_ar)
103
-
104
- Write-AnsibleLog "INFO - creating named pipe '$pipe_name'" "async_wrapper"
105
- $pipe = New-Object -TypeName System.IO.Pipes.NamedPipeServerStream -ArgumentList @(
106
- $pipe_name,
107
- [System.IO.Pipes.PipeDirection]::Out,
108
- 1,
109
- [System.IO.Pipes.PipeTransmissionMode]::Byte,
110
- [System.IO.Pipes.PipeOptions]::Asynchronous,
111
- 0,
112
- 0,
113
- $pipe_sec
23
+ [Parameter(Mandatory)]
24
+ [int]
25
+ $StartupTimeout
114
26
  )
115
27
 
28
+ Import-CSharpUtil -Name 'Ansible._Async.cs'
29
+
30
+ $AsyncDir = [Environment]::ExpandEnvironmentVariables($AsyncDir)
31
+ if (-not [Directory]::Exists($asyncDir)) {
32
+ $null = [Directory]::CreateDirectory($asyncDir)
33
+ }
34
+
35
+ $parentProcessId = 0
36
+ $parentProcessHandle = $stdoutReader = $stderrReader = $stdinPipe = $stdoutPipe = $stderrPipe = $asyncProcess = $waitHandle = $null
116
37
  try {
117
- Write-AnsibleLog "INFO - creating async process '$exec_args'" "async_wrapper"
118
- $process = Invoke-CimMethod -ClassName Win32_Process -Name Create -Arguments @{CommandLine = $exec_args }
119
- $rc = $process.ReturnValue
120
-
121
- Write-AnsibleLog "INFO - return value from async process exec: $rc" "async_wrapper"
122
- if ($rc -ne 0) {
123
- $error_msg = switch ($rc) {
124
- 2 { "Access denied" }
125
- 3 { "Insufficient privilege" }
126
- 8 { "Unknown failure" }
127
- 9 { "Path not found" }
128
- 21 { "Invalid parameter" }
129
- default { "Other" }
38
+ $utf8 = [UTF8Encoding]::new($false)
39
+ $stdinPipe = [AnonymousPipeServerStream]::new([PipeDirection]::Out, [HandleInheritability]::Inheritable)
40
+ $stdoutPipe = [AnonymousPipeServerStream]::new([PipeDirection]::In, [HandleInheritability]::Inheritable)
41
+ $stderrPipe = [AnonymousPipeServerStream]::new([PipeDirection]::In, [HandleInheritability]::Inheritable)
42
+ $stdoutReader = [StreamReader]::new($stdoutPipe, $utf8, $false)
43
+ $stderrReader = [StreamReader]::new($stderrPipe, $utf8, $false)
44
+ $clientWaitHandle = $waitHandle = [Ansible._Async.AsyncUtil]::CreateInheritableEvent()
45
+
46
+ $stdinHandle = $stdinPipe.ClientSafePipeHandle
47
+ $stdoutHandle = $stdoutPipe.ClientSafePipeHandle
48
+ $stderrHandle = $stderrPipe.ClientSafePipeHandle
49
+
50
+ $executable = if ($PSVersionTable.PSVersion -lt '6.0') {
51
+ 'powershell.exe'
52
+ }
53
+ else {
54
+ 'pwsh.exe'
55
+ }
56
+ $executablePath = Join-Path -Path $PSHome -ChildPath $executable
57
+
58
+ # We need to escape the job of the current process to allow the async
59
+ # process to outlive the Windows job. If the current process is not part of
60
+ # a job or job allows us to breakaway we can spawn the process directly.
61
+ # Otherwise we use WMI Win32_Process.Create to create a process as our user
62
+ # outside the job and use that as the async process parent. The winrm and
63
+ # ssh connection plugin allows breaking away from the job but psrp does not.
64
+ if (-not [Ansible._Async.AsyncUtil]::CanCreateBreakawayProcess()) {
65
+ # We hide the console window and suspend the process to avoid it running
66
+ # anything. We only need the process to be created outside the job and not
67
+ # for it to run.
68
+ $psi = New-CimInstance -ClassName Win32_ProcessStartup -ClientOnly -Property @{
69
+ CreateFlags = [uint32]4 # CREATE_SUSPENDED
70
+ ShowWindow = [uint16]0 # SW_HIDE
71
+ }
72
+ $procInfo = Invoke-CimMethod -ClassName Win32_Process -Name Create -Arguments @{
73
+ CommandLine = $executablePath
74
+ ProcessStartupInformation = $psi
75
+ }
76
+ $rc = $procInfo.ReturnValue
77
+ if ($rc -ne 0) {
78
+ $msg = switch ($rc) {
79
+ 2 { "Access denied" }
80
+ 3 { "Insufficient privilege" }
81
+ 8 { "Unknown failure" }
82
+ 9 { "Path not found" }
83
+ 21 { "Invalid parameter" }
84
+ default { "Other" }
85
+ }
86
+ throw "Failed to start async parent process: $rc $msg"
130
87
  }
131
- throw "Failed to start async process: $rc ($error_msg)"
88
+
89
+ # WMI returns a UInt32, we want the signed equivalent of those bytes.
90
+ $parentProcessId = [Convert]::ToInt32(
91
+ [Convert]::ToString($procInfo.ProcessId, 16),
92
+ 16)
93
+
94
+ $parentProcessHandle = [Ansible._Async.AsyncUtil]::OpenProcessAsParent($parentProcessId)
95
+ $clientWaitHandle = [Ansible._Async.AsyncUtil]::DuplicateHandleToProcess($waitHandle, $parentProcessHandle)
96
+ $stdinHandle = [Ansible._Async.AsyncUtil]::DuplicateHandleToProcess($stdinHandle, $parentProcessHandle)
97
+ $stdoutHandle = [Ansible._Async.AsyncUtil]::DuplicateHandleToProcess($stdoutHandle, $parentProcessHandle)
98
+ $stderrHandle = [Ansible._Async.AsyncUtil]::DuplicateHandleToProcess($stderrHandle, $parentProcessHandle)
99
+ $stdinPipe.DisposeLocalCopyOfClientHandle()
100
+ $stdoutPipe.DisposeLocalCopyOfClientHandle()
101
+ $stderrPipe.DisposeLocalCopyOfClientHandle()
132
102
  }
133
- $watchdog_pid = $process.ProcessId
134
- Write-AnsibleLog "INFO - created async process PID: $watchdog_pid" "async_wrapper"
135
103
 
136
- # populate initial results before we send the async data to avoid result race
104
+ $localJid = "$AsyncJid.$pid"
105
+ $resultsPath = [Path]::Combine($AsyncDir, $localJid)
106
+
107
+ $bootstrapWrapper = Get-AnsibleScript -Name bootstrap_wrapper.ps1
108
+ $execAction = Get-AnsibleExecWrapper -EncodeInputOutput
109
+
110
+ $execAction.Parameters.ActionParameters = @{
111
+ ResultPath = $resultsPath
112
+ WaitHandleId = [Int64]$clientWaitHandle.DangerousGetHandle()
113
+ }
114
+ $execWrapper = @{
115
+ name = 'exec_wrapper-async.ps1'
116
+ script = $execAction.Script
117
+ params = $execAction.Parameters
118
+ } | ConvertTo-Json -Compress -Depth 99
119
+ $asyncInput = "$execWrapper`n`0`0`0`0`n$($execAction.InputData)"
120
+
121
+ $encCommand = [Convert]::ToBase64String([Encoding]::Unicode.GetBytes($bootstrapWrapper.Script))
122
+ $asyncCommand = "`"$executablePath`" -NonInteractive -NoProfile -ExecutionPolicy Bypass -EncodedCommand $encCommand"
123
+
124
+ $asyncProcess = [Ansible._Async.AsyncUtil]::CreateAsyncProcess(
125
+ $executablePath,
126
+ $asyncCommand,
127
+ $stdinHandle,
128
+ $stdoutHandle,
129
+ $stderrHandle,
130
+ $clientWaitHandle,
131
+ $parentProcessHandle,
132
+ $stdoutReader,
133
+ $stderrReader)
134
+
135
+ # We need to write the result file before the process is started to ensure
136
+ # it can read the file.
137
137
  $result = @{
138
138
  started = 1
139
139
  finished = 0
140
- results_file = $results_path
141
- ansible_job_id = $local_jid
140
+ results_file = $resultsPath
141
+ ansible_job_id = $localJid
142
142
  _ansible_suppress_tmpdir_delete = $true
143
- ansible_async_watchdog_pid = $watchdog_pid
143
+ ansible_async_watchdog_pid = $asyncProcess.ProcessId
144
+ }
145
+ $resultJson = ConvertTo-Json -InputObject $result -Depth 99 -Compress
146
+ [File]::WriteAllText($resultsPath, $resultJson, $utf8)
147
+
148
+ if ($parentProcessHandle) {
149
+ [Ansible._Async.AsyncUtil]::CloseHandleInProcess($stdinHandle, $parentProcessHandle)
150
+ [Ansible._Async.AsyncUtil]::CloseHandleInProcess($stdoutHandle, $parentProcessHandle)
151
+ [Ansible._Async.AsyncUtil]::CloseHandleInProcess($stderrHandle, $parentProcessHandle)
152
+ [Ansible._Async.AsyncUtil]::CloseHandleInProcess($clientWaitHandle, $parentProcessHandle)
153
+ }
154
+ else {
155
+ $stdinPipe.DisposeLocalCopyOfClientHandle()
156
+ $stdoutPipe.DisposeLocalCopyOfClientHandle()
157
+ $stderrPipe.DisposeLocalCopyOfClientHandle()
158
+ }
159
+
160
+ [Ansible._Async.AsyncUtil]::ResumeThread($asyncProcess.Thread)
161
+
162
+ # If writing to the pipe fails the process has already ended.
163
+ $procAlive = $true
164
+ $procIn = [StreamWriter]::new($stdinPipe, $utf8)
165
+ try {
166
+ $procIn.WriteLine($asyncInput)
167
+ $procIn.Flush()
168
+ $procIn.Dispose()
169
+ }
170
+ catch [IOException] {
171
+ $procAlive = $false
144
172
  }
145
173
 
146
- Write-AnsibleLog "INFO - writing initial async results to '$results_path'" "async_wrapper"
147
- $result_json = ConvertTo-Json -InputObject $result -Depth 99 -Compress
148
- Set-Content $results_path -Value $result_json
149
-
150
- $np_timeout = $Payload.async_startup_timeout * 1000
151
- Write-AnsibleLog "INFO - waiting for async process to connect to named pipe for $np_timeout milliseconds" "async_wrapper"
152
- $wait_async = $pipe.BeginWaitForConnection($null, $null)
153
- $wait_async.AsyncWaitHandle.WaitOne($np_timeout) > $null
154
- if (-not $wait_async.IsCompleted) {
155
- $msg = "Ansible encountered a timeout while waiting for the async task to start and connect to the named"
156
- $msg += "pipe. This can be affected by the performance of the target - you can increase this timeout using"
157
- $msg += "WIN_ASYNC_STARTUP_TIMEOUT or just for this host using the win_async_startup_timeout hostvar if "
158
- $msg += "this keeps happening."
159
- throw $msg
174
+ if ($procAlive) {
175
+ # Wait for the process to signal it has started the async task or if it
176
+ # has ended early/timed out.
177
+ $waitTimespan = [TimeSpan]::FromSeconds($StartupTimeout)
178
+ $handleIdx = [WaitHandle]::WaitAny(
179
+ @(
180
+ [Ansible._Async.ManagedWaitHandle]::new($waitHandle),
181
+ [Ansible._Async.ManagedWaitHandle]::new($asyncProcess.Process)
182
+ ),
183
+ $waitTimespan)
184
+ if ($handleIdx -eq [WaitHandle]::WaitTimeout) {
185
+ $msg = -join @(
186
+ "Ansible encountered a timeout while waiting for the async task to start and signal it has started. "
187
+ "This can be affected by the performance of the target - you can increase this timeout using "
188
+ "WIN_ASYNC_STARTUP_TIMEOUT or just for this host using the ansible_win_async_startup_timeout hostvar "
189
+ "if this keeps happening."
190
+ )
191
+ throw $msg
192
+ }
193
+ $procAlive = $handleIdx -eq 0
160
194
  }
161
- $pipe.EndWaitForConnection($wait_async)
162
195
 
163
- Write-AnsibleLog "INFO - writing exec_wrapper and payload to async process" "async_wrapper"
164
- $pipe.Write($payload_bytes, 0, $payload_bytes.Count)
165
- $pipe.Flush()
166
- $pipe.WaitForPipeDrain()
196
+ if ($procAlive) {
197
+ $resultJson
198
+ }
199
+ else {
200
+ # If the process had ended before it signaled it was ready, we return
201
+ # back the raw output and hope it contains an error.
202
+ Remove-Item -LiteralPath $resultsPath -ErrorAction Ignore
203
+
204
+ $stdout = $asyncProcess.StdoutReader.GetAwaiter().GetResult()
205
+ $stderr = $asyncProcess.StderrReader.GetAwaiter().GetResult()
206
+ $rc = [Ansible._Async.AsyncUtil]::GetProcessExitCode($asyncProcess.Process)
207
+
208
+ $host.UI.WriteLine($stdout)
209
+ Write-PowerShellClixmlStderr -Output $stderr
210
+ $host.SetShouldExit($rc)
211
+ }
167
212
  }
168
213
  finally {
169
- $pipe.Close()
214
+ if ($parentProcessHandle) { $parentProcessHandle.Dispose() }
215
+ if ($parentProcessId) {
216
+ Stop-Process -Id $parentProcessId -Force -ErrorAction Ignore
217
+ }
218
+ if ($stdoutReader) { $stdoutReader.Dispose() }
219
+ if ($stderrReader) { $stderrReader.Dispose() }
220
+ if ($stdinPipe) { $stdinPipe.Dispose() }
221
+ if ($stdoutPipe) { $stdoutPipe.Dispose() }
222
+ if ($stderrPipe) { $stderrPipe.Dispose() }
223
+ if ($asyncProcess) { $asyncProcess.Dispose() }
224
+ if ($waitHandle) { $waitHandle.Dispose() }
170
225
  }
171
-
172
- Write-AnsibleLog "INFO - outputting initial async result: $result_json" "async_wrapper"
173
- Write-Output -InputObject $result_json
174
- Write-AnsibleLog "INFO - ending async_wrapper" "async_wrapper"
@@ -1,162 +1,107 @@
1
- # (c) 2018 Ansible Project
1
+ # (c) 2025 Ansible Project
2
2
  # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
3
3
 
4
- param(
5
- [Parameter(Mandatory = $true)][System.Collections.IDictionary]$Payload
6
- )
7
-
8
- #Requires -Module Ansible.ModuleUtils.AddType
9
- #AnsibleRequires -CSharpUtil Ansible.AccessToken
10
4
  #AnsibleRequires -CSharpUtil Ansible.Become
11
5
 
12
- $ErrorActionPreference = "Stop"
6
+ using namespace System.Collections
7
+ using namespace System.Diagnostics
8
+ using namespace System.IO
9
+ using namespace System.Management.Automation
10
+ using namespace System.Net
11
+ using namespace System.Text
12
+
13
+ [CmdletBinding()]
14
+ param (
15
+ [Parameter()]
16
+ [AllowEmptyString()]
17
+ [string]
18
+ $BecomeUser,
19
+
20
+ [Parameter()]
21
+ [SecureString]
22
+ $BecomePassword,
23
+
24
+ [Parameter()]
25
+ [string]
26
+ $LogonType = 'Interactive',
27
+
28
+ [Parameter()]
29
+ [string]
30
+ $LogonFlags = 'WithProfile'
31
+ )
13
32
 
14
- Write-AnsibleLog "INFO - starting become_wrapper" "become_wrapper"
33
+ Import-CSharpUtil -Name 'Ansible.AccessToken.cs', 'Ansible.Become.cs', 'Ansible.Process.cs'
15
34
 
16
- Function Get-EnumValue($enum, $flag_type, $value) {
17
- $raw_enum_value = $value.Replace('_', '')
18
- try {
19
- $enum_value = [Enum]::Parse($enum, $raw_enum_value, $true)
20
- }
21
- catch [System.ArgumentException] {
22
- $valid_options = [Enum]::GetNames($enum) | ForEach-Object -Process {
23
- (($_ -creplace "(.)([A-Z][a-z]+)", '$1_$2') -creplace "([a-z0-9])([A-Z])", '$1_$2').ToString().ToLower()
24
- }
25
- throw "become_flags $flag_type value '$value' is not valid, valid values are: $($valid_options -join ", ")"
26
- }
27
- return $enum_value
35
+ # We need to set password to the value of NullString so a null password is
36
+ # preserved when crossing the .NET boundary. If we pass $null it will
37
+ # automatically be converted to "" and we need to keep the distinction for
38
+ # accounts that don't have a password and when someone wants to become without
39
+ # knowing the password.
40
+ $password = [NullString]::Value
41
+ if ($null -ne $BecomePassword) {
42
+ $password = [NetworkCredential]::new("", $BecomePassword).Password
28
43
  }
29
44
 
30
- Function Get-BecomeFlag($flags) {
31
- $logon_type = [Ansible.AccessToken.LogonType]::Interactive
32
- $logon_flags = [Ansible.Become.LogonFlags]::WithProfile
33
-
34
- if ($null -eq $flags -or $flags -eq "") {
35
- $flag_split = @()
36
- }
37
- elseif ($flags -is [string]) {
38
- $flag_split = $flags.Split(" ")
39
- }
40
- else {
41
- throw "become_flags must be a string, was $($flags.GetType())"
42
- }
43
-
44
- foreach ($flag in $flag_split) {
45
- $split = $flag.Split("=")
46
- if ($split.Count -ne 2) {
47
- throw "become_flags entry '$flag' is in an invalid format, must be a key=value pair"
48
- }
49
- $flag_key = $split[0]
50
- $flag_value = $split[1]
51
- if ($flag_key -eq "logon_type") {
52
- $enum_details = @{
53
- enum = [Ansible.AccessToken.LogonType]
54
- flag_type = $flag_key
55
- value = $flag_value
56
- }
57
- $logon_type = Get-EnumValue @enum_details
58
- }
59
- elseif ($flag_key -eq "logon_flags") {
60
- $logon_flag_values = $flag_value.Split(",")
61
- $logon_flags = 0 -as [Ansible.Become.LogonFlags]
62
- foreach ($logon_flag_value in $logon_flag_values) {
63
- if ($logon_flag_value -eq "") {
64
- continue
65
- }
66
- $enum_details = @{
67
- enum = [Ansible.Become.LogonFlags]
68
- flag_type = $flag_key
69
- value = $logon_flag_value
70
- }
71
- $logon_flag = Get-EnumValue @enum_details
72
- $logon_flags = $logon_flags -bor $logon_flag
73
- }
74
- }
75
- else {
76
- throw "become_flags key '$flag_key' is not a valid runas flag, must be 'logon_type' or 'logon_flags'"
77
- }
78
- }
79
-
80
- return $logon_type, [Ansible.Become.LogonFlags]$logon_flags
45
+ $executable = if ($PSVersionTable.PSVersion -lt '6.0') {
46
+ 'powershell.exe'
81
47
  }
82
-
83
- Write-AnsibleLog "INFO - loading C# become code" "become_wrapper"
84
- $add_type_b64 = $Payload.powershell_modules["Ansible.ModuleUtils.AddType"]
85
- $add_type = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($add_type_b64))
86
- New-Module -Name Ansible.ModuleUtils.AddType -ScriptBlock ([ScriptBlock]::Create($add_type)) | Import-Module > $null
87
-
88
- $new_tmp = [System.Environment]::ExpandEnvironmentVariables($Payload.module_args["_ansible_remote_tmp"])
89
- $access_def = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Payload.csharp_utils["Ansible.AccessToken"]))
90
- $become_def = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Payload.csharp_utils["Ansible.Become"]))
91
- $process_def = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Payload.csharp_utils["Ansible.Process"]))
92
- Add-CSharpType -References $access_def, $become_def, $process_def -TempPath $new_tmp -IncludeDebugInfo
93
-
94
- $username = $Payload.become_user
95
- $password = $Payload.become_password
96
- # We need to set password to the value of NullString so a null password is preserved when crossing the .NET
97
- # boundary. If we pass $null it will automatically be converted to "" and we need to keep the distinction for
98
- # accounts that don't have a password and when someone wants to become without knowing the password.
99
- if ($null -eq $password) {
100
- $password = [NullString]::Value
48
+ else {
49
+ 'pwsh.exe'
101
50
  }
51
+ $executablePath = Join-Path -Path $PSHome -ChildPath $executable
102
52
 
103
- try {
104
- $logon_type, $logon_flags = Get-BecomeFlag -flags $Payload.become_flags
105
- }
106
- catch {
107
- Write-AnsibleError -Message "internal error: failed to parse become_flags '$($Payload.become_flags)'" -ErrorRecord $_
108
- $host.SetShouldExit(1)
109
- return
110
- }
111
- Write-AnsibleLog "INFO - parsed become input, user: '$username', type: '$logon_type', flags: '$logon_flags'" "become_wrapper"
53
+ $actionInfo = Get-AnsibleExecWrapper -EncodeInputOutput
54
+ $bootstrapManifest = ConvertTo-Json -InputObject @{
55
+ n = "exec_wrapper-become-$([Guid]::NewGuid()).ps1"
56
+ s = $actionInfo.Script
57
+ p = $actionInfo.Parameters
58
+ } -Depth 99 -Compress
112
59
 
113
60
  # NB: CreateProcessWithTokenW commandline maxes out at 1024 chars, must
114
- # bootstrap via small wrapper which contains the exec_wrapper passed through the
115
- # stdin pipe. Cannot use 'powershell -' as the $ErrorActionPreference is always
116
- # set to Stop and cannot be changed. Also need to split the payload from the wrapper to prevent potentially
117
- # sensitive content from being logged by the scriptblock logger.
118
- $bootstrap_wrapper = {
119
- [Console]::InputEncoding = [Console]::OutputEncoding = New-Object System.Text.UTF8Encoding
120
- $ew = [System.Console]::In.ReadToEnd()
121
- $split_parts = $ew.Split(@("`0`0`0`0"), 2, [StringSplitOptions]::RemoveEmptyEntries)
122
- Set-Variable -Name json_raw -Value $split_parts[1]
123
- &([ScriptBlock]::Create($split_parts[0]))
61
+ # bootstrap via small wrapper to invoke the exec_wrapper. Strings are used to
62
+ # avoid sanity tests like aliases and spaces.
63
+ [string]$command = @'
64
+ $m=foreach($i in $input){
65
+ if([string]::Equals($i,"`0`0`0`0")){break}
66
+ $i
124
67
  }
125
- $exec_command = [System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($bootstrap_wrapper.ToString()))
126
- $lp_command_line = "powershell.exe -NonInteractive -NoProfile -ExecutionPolicy Bypass -EncodedCommand $exec_command"
127
- $lp_current_directory = $env:SystemRoot # TODO: should this be set to the become user's profile dir?
128
-
129
- # pop the become_wrapper action so we don't get stuck in a loop
130
- $Payload.actions = $Payload.actions[1..99]
131
- # we want the output from the exec_wrapper to be base64 encoded to preserve unicode chars
132
- $Payload.encoded_output = $true
133
-
134
- $payload_json = ConvertTo-Json -InputObject $Payload -Depth 99 -Compress
135
- # delimit the payload JSON from the wrapper to keep sensitive contents out of scriptblocks (which can be logged)
136
- $exec_wrapper = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Payload.exec_wrapper))
137
- $exec_wrapper += "`0`0`0`0" + $payload_json
138
-
68
+ $m=$m|ConvertFrom-Json
69
+ $p=@{}
70
+ foreach($o in $m.p.PSObject.Properties){$p[$o.Name]=$o.Value}
71
+ $c=[System.Management.Automation.Language.Parser]::ParseInput($m.s,$m.n,[ref]$null,[ref]$null).GetScriptBlock()
72
+ $input | & $c @p
73
+ '@
74
+
75
+ # Strip out any leading or trailing whitespace and remove empty lines.
76
+ $command = @(
77
+ ($command -split "\r?\n") |
78
+ ForEach-Object { $_.Trim() } |
79
+ Where-Object { -not [string]::IsNullOrWhiteSpace($_) }
80
+ ) -join "`n"
81
+
82
+ $encCommand = [Convert]::ToBase64String([Encoding]::Unicode.GetBytes($command))
83
+ # Shortened version of '-NonInteractive -NoProfile -ExecutionPolicy Bypass -EncodedCommand $encCommand'
84
+ $commandLine = "$executable -noni -nop -ex Bypass -e $encCommand"
85
+ $result = [Ansible.Become.BecomeUtil]::CreateProcessAsUser(
86
+ $BecomeUser,
87
+ $password,
88
+ $LogonFlags,
89
+ $LogonType,
90
+ $executablePath,
91
+ $commandLine,
92
+ $env:SystemRoot,
93
+ $null,
94
+ "$bootstrapManifest`n`0`0`0`0`n$($actionInfo.InputData)")
95
+
96
+ $stdout = $result.StandardOut
139
97
  try {
140
- Write-AnsibleLog "INFO - starting become process '$lp_command_line'" "become_wrapper"
141
- $result = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($username, $password, $logon_flags, $logon_type,
142
- $null, $lp_command_line, $lp_current_directory, $null, $exec_wrapper)
143
- Write-AnsibleLog "INFO - become process complete with rc: $($result.ExitCode)" "become_wrapper"
144
- $stdout = $result.StandardOut
145
- try {
146
- $stdout = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($stdout))
147
- }
148
- catch [FormatException] {
149
- # output wasn't Base64, ignore as it may contain an error message we want to pass to Ansible
150
- Write-AnsibleLog "WARN - become process stdout was not base64 encoded as expected: $stdout"
151
- }
152
-
153
- $host.UI.WriteLine($stdout)
154
- $host.UI.WriteErrorLine($result.StandardError.Trim())
155
- $host.SetShouldExit($result.ExitCode)
98
+ $stdout = [Encoding]::UTF8.GetString([Convert]::FromBase64String($stdout))
156
99
  }
157
- catch {
158
- Write-AnsibleError -Message "internal error: failed to become user '$username'" -ErrorRecord $_
159
- $host.SetShouldExit(1)
100
+ catch [FormatException] {
101
+ # output wasn't Base64, ignore as it may contain an error message we want to pass to Ansible
102
+ $null = $_
160
103
  }
161
104
 
162
- Write-AnsibleLog "INFO - ending become_wrapper" "become_wrapper"
105
+ $Host.UI.WriteLine($stdout)
106
+ Write-PowerShellClixmlStderr -Output $result.StandardError
107
+ $Host.SetShouldExit($result.ExitCode)
@@ -1,12 +1,27 @@
1
- try { [Console]::InputEncoding = [Console]::OutputEncoding = New-Object System.Text.UTF8Encoding } catch { $null = $_ }
2
-
3
- if ($PSVersionTable.PSVersion -lt [Version]"3.0") {
4
- '{"failed":true,"msg":"Ansible requires PowerShell v3.0 or newer"}'
1
+ if ($PSVersionTable.PSVersion -lt [Version]"5.1") {
2
+ '{"failed":true,"msg":"Ansible requires PowerShell v5.1"}'
5
3
  exit 1
6
4
  }
7
5
 
8
- $exec_wrapper_str = $input | Out-String
9
- $split_parts = $exec_wrapper_str.Split(@("`0`0`0`0"), 2, [StringSplitOptions]::RemoveEmptyEntries)
10
- If (-not $split_parts.Length -eq 2) { throw "invalid payload" }
11
- Set-Variable -Name json_raw -Value $split_parts[1]
12
- & ([ScriptBlock]::Create($split_parts[0]))
6
+ # First input is a JSON string with name/script/params of what to run. This
7
+ # ends with a line of 4 null bytes and subsequent input is piped to the code
8
+ # provided.
9
+ $codeJson = foreach ($in in $input) {
10
+ if ([string]::Equals($in, "`0`0`0`0")) {
11
+ break
12
+ }
13
+ $in
14
+ }
15
+ $code = ConvertFrom-Json -InputObject $codeJson
16
+ $splat = @{}
17
+ foreach ($obj in $code.params.PSObject.Properties) {
18
+ $splat[$obj.Name] = $obj.Value
19
+ }
20
+
21
+ $cmd = [System.Management.Automation.Language.Parser]::ParseInput(
22
+ $code.script,
23
+ "$($code.name).ps1", # Name is used in stack traces.
24
+ [ref]$null,
25
+ [ref]$null).GetScriptBlock()
26
+
27
+ $input | & $cmd @splat