2018-08-28 23:44:30 +00:00
|
|
|
#!powershell
|
|
|
|
|
2018-08-31 01:13:51 +00:00
|
|
|
# Copyright: (c) 2017, Ansible Project
|
|
|
|
# Copyright: (c) 2018, Dag Wieers (@dagwieers) <dag@wieers.com>
|
2018-08-28 23:44:30 +00:00
|
|
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
|
|
|
|
|
|
#Requires -Module Ansible.ModuleUtils.Legacy
|
2018-08-31 01:13:51 +00:00
|
|
|
#Requires -Module Ansible.ModuleUtils.SID
|
2018-08-28 23:44:30 +00:00
|
|
|
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
|
2018-08-31 01:13:51 +00:00
|
|
|
# NOTE: Ensure we get proper debug information when things fall over
|
|
|
|
trap {
|
|
|
|
if ($null -eq $result) { $result = @{} }
|
|
|
|
$result.exception = "$($_ | Out-String)`r`n$($_.ScriptStackTrace)"
|
|
|
|
Fail-Json -obj $result -message "Uncaught exception: $($_.Exception.Message)"
|
|
|
|
}
|
|
|
|
|
2018-08-28 23:44:30 +00:00
|
|
|
$params = Parse-Args -arguments $args -supports_check_mode $true
|
|
|
|
|
2018-08-31 01:13:51 +00:00
|
|
|
$process_name_exact = Get-AnsibleParam -obj $params -name "process_name_exact" -type "list"
|
|
|
|
$process_name_pattern = Get-AnsibleParam -obj $params -name "process_name_pattern" -type "str"
|
|
|
|
$process_id = Get-AnsibleParam -obj $params -name "pid" -type "int" -default 0 # pid is a reserved variable in PowerShell, using process_id instead.
|
2018-08-28 23:44:30 +00:00
|
|
|
$owner = Get-AnsibleParam -obj $params -name "owner" -type "str"
|
|
|
|
$sleep = Get-AnsibleParam -obj $params -name "sleep" -type "int" -default 1
|
|
|
|
$pre_wait_delay = Get-AnsibleParam -obj $params -name "pre_wait_delay" -type "int" -default 0
|
|
|
|
$post_wait_delay = Get-AnsibleParam -obj $params -name "post_wait_delay" -type "int" -default 0
|
|
|
|
$process_min_count = Get-AnsibleParam -obj $params -name "process_min_count" -type "int" -default 1
|
2018-08-31 01:13:51 +00:00
|
|
|
$state = Get-AnsibleParam -obj $params -name "state" -type "str" -default "present" -validateset "absent","present"
|
2018-08-28 23:44:30 +00:00
|
|
|
$timeout = Get-AnsibleParam -obj $params -name "timeout" -type "int" -default 300
|
|
|
|
|
|
|
|
$result = @{
|
|
|
|
changed = $false
|
2018-08-31 01:13:51 +00:00
|
|
|
elapsed = 0
|
|
|
|
matched_processes = @()
|
2018-08-28 23:44:30 +00:00
|
|
|
}
|
|
|
|
|
2018-08-31 01:13:51 +00:00
|
|
|
# Validate the input
|
|
|
|
if ($state -eq "absent" -and $sleep -ne 1) {
|
|
|
|
Add-Warning -obj $result -message "Parameter 'sleep' has no effect when waiting for a process to stop."
|
2018-08-28 23:44:30 +00:00
|
|
|
}
|
|
|
|
|
2018-08-31 01:13:51 +00:00
|
|
|
if ($state -eq "absent" -and $process_min_count -ne 1) {
|
|
|
|
Add-Warning -obj $result -message "Parameter 'process_min_count' has no effect when waiting for a process to stop."
|
2018-08-28 23:44:30 +00:00
|
|
|
}
|
|
|
|
|
2018-08-31 01:13:51 +00:00
|
|
|
if (($process_name_exact -or $process_name_pattern) -and $process_id) {
|
|
|
|
Fail-Json -obj $result -message "Parameter 'pid' may not be used with process_name_exact or process_name_pattern."
|
2018-08-28 23:44:30 +00:00
|
|
|
}
|
2018-08-31 01:13:51 +00:00
|
|
|
if ($process_name_exact -and $process_name_pattern) {
|
|
|
|
Fail-Json -obj $result -message "Parameter 'process_name_exact' and 'process_name_pattern' may not be used at the same time."
|
2018-08-28 23:44:30 +00:00
|
|
|
}
|
|
|
|
|
2018-08-31 01:13:51 +00:00
|
|
|
if (-not ($process_name_exact -or $process_name_pattern -or $process_id -or $owner)) {
|
|
|
|
Fail-Json -obj $result -message "At least one of 'process_name_exact', 'process_name_pattern', 'pid' or 'owner' must be supplied."
|
2018-08-28 23:44:30 +00:00
|
|
|
}
|
|
|
|
|
2018-08-31 01:13:51 +00:00
|
|
|
if ($owner -and ("IncludeUserName" -notin (Get-Command -Name Get-Process).Parameters.Keys)) {
|
|
|
|
Fail-Json -obj $result -message "This version of Powershell does not support filtering processes by 'owner'."
|
|
|
|
}
|
2018-08-28 23:44:30 +00:00
|
|
|
|
2018-08-31 01:13:51 +00:00
|
|
|
Function Get-FilteredProcesses {
|
2018-08-28 23:44:30 +00:00
|
|
|
[cmdletbinding()]
|
|
|
|
Param(
|
|
|
|
[String]
|
|
|
|
$Owner,
|
|
|
|
$ProcessNameExact,
|
|
|
|
$ProcessNamePattern,
|
|
|
|
[int]
|
|
|
|
$ProcessId
|
|
|
|
)
|
2018-08-31 01:13:51 +00:00
|
|
|
|
|
|
|
$FilteredProcesses = @()
|
|
|
|
|
|
|
|
try {
|
|
|
|
$Processes = Get-Process -IncludeUserName
|
|
|
|
$SupportsUserNames = $true
|
|
|
|
} catch [System.Management.Automation.ParameterBindingException] {
|
|
|
|
$Processes = Get-Process
|
|
|
|
$SupportsUserNames = $false
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach ($Process in $Processes) {
|
|
|
|
|
|
|
|
# If a process name was specified in the filter, validate that here.
|
|
|
|
if ($ProcessNamePattern) {
|
|
|
|
if ($Process.ProcessName -notmatch $ProcessNamePattern) {
|
|
|
|
continue
|
|
|
|
}
|
2018-08-28 23:44:30 +00:00
|
|
|
}
|
2018-08-31 01:13:51 +00:00
|
|
|
|
|
|
|
# If a process name was specified in the filter, validate that here.
|
|
|
|
if ($ProcessNameExact -is [Array]) {
|
|
|
|
if ($ProcessNameExact -notcontains $Process.ProcessName) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
} elseif ($ProcessNameExact) {
|
|
|
|
if ($ProcessNameExact -ne $Process.ProcessName) {
|
|
|
|
continue
|
2018-08-28 23:44:30 +00:00
|
|
|
}
|
|
|
|
}
|
2018-08-31 01:13:51 +00:00
|
|
|
|
|
|
|
# If a PID was specified in the filter, validate that here.
|
|
|
|
if ($ProcessId -and $ProcessId -ne 0) {
|
|
|
|
if ($ProcessId -ne $Process.Id) {
|
|
|
|
continue
|
|
|
|
}
|
2018-08-28 23:44:30 +00:00
|
|
|
}
|
2018-08-31 01:13:51 +00:00
|
|
|
|
|
|
|
# If an owner was specified in the filter, validate that here.
|
|
|
|
if ($Owner) {
|
|
|
|
if (-not $Process.UserName) {
|
|
|
|
continue
|
|
|
|
} elseif ((Convert-ToSID($Owner)) -ne (Convert-ToSID($Process.UserName))) { # NOTE: This is rather expensive
|
|
|
|
continue
|
|
|
|
}
|
2018-08-28 23:44:30 +00:00
|
|
|
}
|
2018-08-31 01:13:51 +00:00
|
|
|
|
|
|
|
if ($SupportsUserNames -eq $true) {
|
|
|
|
$FilteredProcesses += @{ name = $Process.ProcessName; pid = $Process.Id; owner = $Process.UserName }
|
|
|
|
} else {
|
|
|
|
$FilteredProcesses += @{ name = $Process.ProcessName; pid = $Process.Id }
|
2018-08-28 23:44:30 +00:00
|
|
|
}
|
|
|
|
}
|
2018-08-31 01:13:51 +00:00
|
|
|
|
|
|
|
return ,$FilteredProcesses
|
2018-08-28 23:44:30 +00:00
|
|
|
}
|
|
|
|
|
2018-08-31 01:13:51 +00:00
|
|
|
$module_start = Get-Date
|
2018-08-28 23:44:30 +00:00
|
|
|
Start-Sleep -Seconds $pre_wait_delay
|
2018-08-31 01:13:51 +00:00
|
|
|
|
2018-08-28 23:44:30 +00:00
|
|
|
if ($state -eq "present" ) {
|
2018-08-31 01:13:51 +00:00
|
|
|
|
|
|
|
# Wait for a process to start
|
|
|
|
do {
|
|
|
|
|
|
|
|
$Processes = Get-FilteredProcesses -Owner $owner -ProcessNameExact $process_name_exact -ProcessNamePattern $process_name_pattern -ProcessId $process_id
|
|
|
|
$result.matched_processes = $Processes
|
|
|
|
|
|
|
|
if ($Processes.count -ge $process_min_count) {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
if (((Get-Date) - $module_start).TotalSeconds -gt $timeout) {
|
2018-08-28 23:44:30 +00:00
|
|
|
$result.elapsed = ((Get-Date) - $module_start).TotalSeconds
|
2018-08-31 01:13:51 +00:00
|
|
|
Fail-Json -obj $result -message "Timed out while waiting for process(es) to start"
|
2018-08-28 23:44:30 +00:00
|
|
|
}
|
2018-08-31 01:13:51 +00:00
|
|
|
|
2018-08-28 23:44:30 +00:00
|
|
|
Start-Sleep -Seconds $sleep
|
|
|
|
|
2018-08-31 01:13:51 +00:00
|
|
|
} while ($true)
|
|
|
|
|
|
|
|
} elseif ($state -eq "absent") {
|
|
|
|
|
|
|
|
# Wait for a process to stop
|
|
|
|
$Processes = Get-FilteredProcesses -Owner $owner -ProcessNameExact $process_name_exact -ProcessNamePattern $process_name_pattern -ProcessId $process_id
|
2018-08-28 23:44:30 +00:00
|
|
|
$result.matched_processes = $Processes
|
2018-08-31 01:13:51 +00:00
|
|
|
|
|
|
|
if ($Processes.count -gt 0 ) {
|
|
|
|
try {
|
|
|
|
# This may randomly fail when used on specially protected processes (think: svchost)
|
|
|
|
Wait-Process -Id $Processes.pid -Timeout $timeout
|
|
|
|
} catch [System.TimeoutException] {
|
2018-08-28 23:44:30 +00:00
|
|
|
$result.elapsed = ((Get-Date) - $module_start).TotalSeconds
|
2018-08-31 01:13:51 +00:00
|
|
|
Fail-Json -obj $result -message "Timeout while waiting for process(es) to stop"
|
2018-08-28 23:44:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2018-08-31 01:13:51 +00:00
|
|
|
|
2018-08-28 23:44:30 +00:00
|
|
|
Start-Sleep -Seconds $post_wait_delay
|
|
|
|
$result.elapsed = ((Get-Date) - $module_start).TotalSeconds
|
2018-08-31 01:13:51 +00:00
|
|
|
|
|
|
|
Exit-Json -obj $result
|