/lib/ansible/modules/windows/win_wait_for_process.ps1

https://github.com/debfx/ansible · Powershell · 176 lines · 129 code · 33 blank · 14 comment · 39 complexity · a3879fa6e4893f3f6fdfa1fa79a40191 MD5 · raw file

  1. #!powershell
  2. # Copyright: (c) 2017, Ansible Project
  3. # Copyright: (c) 2018, Dag Wieers (@dagwieers) <dag@wieers.com>
  4. # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
  5. #AnsibleRequires -CSharpUtil Ansible.Basic
  6. #Requires -Module Ansible.ModuleUtils.SID
  7. $spec = @{
  8. options = @{
  9. process_name_exact = @{ type='list' }
  10. process_name_pattern = @{ type='str' }
  11. pid = @{ type='int'; default=0 }
  12. owner = @{ type='str' }
  13. sleep = @{ type='int'; default=1 }
  14. pre_wait_delay = @{ type='int'; default=0 }
  15. post_wait_delay = @{ type='int'; default=0 }
  16. process_min_count = @{ type='int'; default=1 }
  17. state = @{ type='str'; default='present'; choices=@( 'absent', 'present' ) }
  18. timeout = @{ type='int'; default=300 }
  19. }
  20. mutually_exclusive = @(
  21. @( 'pid', 'process_name_exact' ),
  22. @( 'pid', 'process_name_pattern' ),
  23. @( 'process_name_exact', 'process_name_pattern' )
  24. )
  25. required_one_of = @(
  26. ,@( 'owner', 'pid', 'process_name_exact', 'process_name_pattern' )
  27. )
  28. supports_check_mode = $true
  29. }
  30. $module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
  31. $process_name_exact = $module.Params.process_name_exact
  32. $process_name_pattern = $module.Params.process_name_pattern
  33. $process_id = $module.Params.pid # pid is a reserved variable in PowerShell, using process_id instead
  34. $owner = $module.Params.owner
  35. $sleep = $module.Params.sleep
  36. $pre_wait_delay = $module.Params.pre_wait_delay
  37. $post_wait_delay = $module.Params.post_wait_delay
  38. $process_min_count = $module.Params.process_min_count
  39. $state = $module.Params.state
  40. $timeout = $module.Params.timeout
  41. $module.Result.changed = $false
  42. $module.Result.elapsed = 0
  43. $module.Result.matched_processes = @()
  44. # Validate the input
  45. if ($state -eq "absent" -and $sleep -ne 1) {
  46. $module.Warn("Parameter 'sleep' has no effect when waiting for a process to stop.")
  47. }
  48. if ($state -eq "absent" -and $process_min_count -ne 1) {
  49. $module.Warn("Parameter 'process_min_count' has no effect when waiting for a process to stop.")
  50. }
  51. if ($owner -and ("IncludeUserName" -notin (Get-Command -Name Get-Process).Parameters.Keys)) {
  52. $module.FailJson("This version of Powershell does not support filtering processes by 'owner'.")
  53. }
  54. Function Get-FilteredProcesses {
  55. [cmdletbinding()]
  56. Param(
  57. [String]
  58. $Owner,
  59. $ProcessNameExact,
  60. $ProcessNamePattern,
  61. [int]
  62. $ProcessId
  63. )
  64. $FilteredProcesses = @()
  65. try {
  66. $Processes = Get-Process -IncludeUserName
  67. $SupportsUserNames = $true
  68. } catch [System.Management.Automation.ParameterBindingException] {
  69. $Processes = Get-Process
  70. $SupportsUserNames = $false
  71. }
  72. foreach ($Process in $Processes) {
  73. # If a process name was specified in the filter, validate that here.
  74. if ($ProcessNamePattern) {
  75. if ($Process.ProcessName -notmatch $ProcessNamePattern) {
  76. continue
  77. }
  78. }
  79. # If a process name was specified in the filter, validate that here.
  80. if ($ProcessNameExact -is [Array]) {
  81. if ($ProcessNameExact -notcontains $Process.ProcessName) {
  82. continue
  83. }
  84. } elseif ($ProcessNameExact) {
  85. if ($ProcessNameExact -ne $Process.ProcessName) {
  86. continue
  87. }
  88. }
  89. # If a PID was specified in the filter, validate that here.
  90. if ($ProcessId -and $ProcessId -ne 0) {
  91. if ($ProcessId -ne $Process.Id) {
  92. continue
  93. }
  94. }
  95. # If an owner was specified in the filter, validate that here.
  96. if ($Owner) {
  97. if (-not $Process.UserName) {
  98. continue
  99. } elseif ((Convert-ToSID($Owner)) -ne (Convert-ToSID($Process.UserName))) { # NOTE: This is rather expensive
  100. continue
  101. }
  102. }
  103. if ($SupportsUserNames -eq $true) {
  104. $FilteredProcesses += @{ name = $Process.ProcessName; pid = $Process.Id; owner = $Process.UserName }
  105. } else {
  106. $FilteredProcesses += @{ name = $Process.ProcessName; pid = $Process.Id }
  107. }
  108. }
  109. return ,$FilteredProcesses
  110. }
  111. $module_start = Get-Date
  112. Start-Sleep -Seconds $pre_wait_delay
  113. if ($state -eq "present" ) {
  114. # Wait for a process to start
  115. do {
  116. $Processes = Get-FilteredProcesses -Owner $owner -ProcessNameExact $process_name_exact -ProcessNamePattern $process_name_pattern -ProcessId $process_id
  117. $module.Result.matched_processes = $Processes
  118. if ($Processes.count -ge $process_min_count) {
  119. break
  120. }
  121. if (((Get-Date) - $module_start).TotalSeconds -gt $timeout) {
  122. $module.Result.elapsed = ((Get-Date) - $module_start).TotalSeconds
  123. $module.FailJson("Timed out while waiting for process(es) to start")
  124. }
  125. Start-Sleep -Seconds $sleep
  126. } while ($true)
  127. } elseif ($state -eq "absent") {
  128. # Wait for a process to stop
  129. $Processes = Get-FilteredProcesses -Owner $owner -ProcessNameExact $process_name_exact -ProcessNamePattern $process_name_pattern -ProcessId $process_id
  130. $module.Result.matched_processes = $Processes
  131. if ($Processes.count -gt 0 ) {
  132. try {
  133. # This may randomly fail when used on specially protected processes (think: svchost)
  134. Wait-Process -Id $Processes.pid -Timeout $timeout
  135. } catch [System.TimeoutException] {
  136. $module.Result.elapsed = ((Get-Date) - $module_start).TotalSeconds
  137. $module.FailJson("Timeout while waiting for process(es) to stop")
  138. }
  139. }
  140. }
  141. Start-Sleep -Seconds $post_wait_delay
  142. $module.Result.elapsed = ((Get-Date) - $module_start).TotalSeconds
  143. $module.ExitJson()