win_scheduled_task_stat: add new module to get stat on scheduled tasks (#30602)

* win_scheduled_task_stat: add new module to get stat on scheduled tasks

* fixed up linting errors and aliases file

* I should learn how to spell

* removing URI from test

* added state information for the task

* removed argument so task stays running
This commit is contained in:
Jordan Borean 2017-09-22 05:59:06 +10:00 committed by GitHub
commit 59187358ee
11 changed files with 808 additions and 238 deletions

View file

@ -547,7 +547,7 @@ Function Compare-Triggers($task_definition) {
$map = @{
[TASK_TRIGGER_TYPE2]::TASK_TRIGGER_BOOT = @{
mandatory = @()
optional = @('enabled', 'end_boundary', 'execution_time_limit', 'start_boundary')
optional = @('delay', 'enabled', 'end_boundary', 'execution_time_limit', 'start_boundary')
}
[TASK_TRIGGER_TYPE2]::TASK_TRIGGER_DAILY = @{
mandatory = @('start_boundary')

View file

@ -127,8 +127,8 @@ options:
description:
- The time to delay the task from running once the trigger has been
fired.
- Optional when C(type) is C(event), C(logon), C(registration),
C(session_state_change).
- Optional when C(type) is C(boot), C(event), C(logon),
C(registration), C(session_state_change).
- Is in the ISO 8601 Duration format C(P[n]Y[n]M[n]DT[n]H[n]M[n]S).
random_delay:
description:
@ -331,7 +331,7 @@ options:
task after it expires.
- A task expires after the end_boundary has been exceeded for all triggers
associated with the task.
- This is in ISO 8601 DateTime format C(YYYY-MM-DDThh:mm:ss).
- This is in the ISO 8601 Duration format C(P[n]Y[n]M[n]DT[n]H[n]M[n]S).
version_added: '2.5'
disallow_start_if_on_batteries:
description:
@ -348,14 +348,14 @@ options:
description:
- The amount of time allowed to complete the task.
- When not set, the time limit is infinite.
- This is in ISO 8601 DateTime format C(YYYY-MM-DDThh:mm:ss).
- This is in the ISO 8601 Duration format C(P[n]Y[n]M[n]DT[n]H[n]M[n]S).
version_added: '2.5'
hidden:
description:
- Whether the task will be hidden in the UI.
type: bool
version_added: '2.5'
mutliple_instances:
multiple_instances:
description:
- An integer that indicates the behaviour when starting a task that is
already running.
@ -367,7 +367,7 @@ options:
- C(3) will stop other instances of the task and start the new one.
choices: [ 0, 1, 2, 3 ]
version_added: '2.5'
priortiy:
priority:
description:
- The priority level (0-10) of the task.
- When creating a new task the default if C(7).
@ -385,7 +385,7 @@ options:
- If this is set then C(restart_count) must also be set.
- The maximum allowed time is 31 days.
- The minimum allowed time is 1 minute.
- This is in ISO 8601 DateTime format C(YYYY-MM-DDThh:mm:ss).
- This is in the ISO 8601 Duration format C(P[n]Y[n]M[n]DT[n]H[n]M[n]S).
version_added: '2.5'
run_only_if_idle:
description:

View file

@ -0,0 +1,320 @@
#!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.CamelConversion
#Requires -Module Ansible.ModuleUtils.Legacy
#Requires -Module Ansible.ModuleUtils.SID
$params = Parse-Args -arguments $args
$path = Get-AnsibleParam -obj $params -name "path" -type "str" -default "\"
$name = Get-AnsibleParam -obj $params -name "name" -type "str"
$result = @{
changed = $false
}
Add-Type -TypeDefinition @"
public enum TASK_ACTION_TYPE
{
TASK_ACTION_EXEC = 0,
// The below are not supported and are only kept for documentation purposes
TASK_ACTION_COM_HANDLER = 5,
TASK_ACTION_SEND_EMAIL = 6,
TASK_ACTION_SHOW_MESSAGE = 7
}
public enum TASK_LOGON_TYPE
{
TASK_LOGON_NONE = 0,
TASK_LOGON_PASSWORD = 1,
TASK_LOGON_S4U = 2,
TASK_LOGON_INTERACTIVE_TOKEN = 3,
TASK_LOGON_GROUP = 4,
TASK_LOGON_SERVICE_ACCOUNT = 5,
TASK_LOGON_INTERACTIVE_TOKEN_OR_PASSWORD = 6
}
public enum TASK_RUN_LEVEL
{
TASK_RUNLEVEL_LUA = 0,
TASK_RUNLEVEL_HIGHEST = 1
}
public enum TASK_STATE
{
TASK_STATE_UNKNOWN = 0,
TASK_STATE_DISABLED = 1,
TASK_STATE_QUEUED = 2,
TASK_STATE_READY = 3,
TASK_STATE_RUNNING = 4
}
public enum TASK_TRIGGER_TYPE2
{
TASK_TRIGGER_EVENT = 0,
TASK_TRIGGER_TIME = 1,
TASK_TRIGGER_DAILY = 2,
TASK_TRIGGER_WEEKLY = 3,
TASK_TRIGGER_MONTHLY = 4,
TASK_TRIGGER_MONTHLYDOW = 5,
TASK_TRIGGER_IDLE = 6,
TASK_TRIGGER_REGISTRATION = 7,
TASK_TRIGGER_BOOT = 8,
TASK_TRIGGER_LOGON = 9,
TASK_TRIGGER_SESSION_STATE_CHANGE = 11
}
"@
Function Get-PropertyValue($task_property, $com, $property) {
$raw_value = $com.$property
if ($raw_value -eq $null) {
return $null
} elseif ($raw_value.GetType().Name -eq "__ComObject") {
$com_values = @{}
$properties = Get-Member -InputObject $raw_value -MemberType Property | % {
$com_value = Get-PropertyValue -task_property $property -com $raw_value -property $_.Name
$com_values.$property = $com_value
}
return ,$com_values
}
switch ($property) {
DaysOfWeek {
$value_list = @()
$map = @(
@{ day = "sunday"; bitwise = 0x01 }
@{ day = "monday"; bitwise = 0x02 }
@{ day = "tuesday"; bitwise = 0x04 }
@{ day = "wednesday"; bitwise = 0x08 }
@{ day = "thursday"; bitwise = 0x10 }
@{ day = "friday"; bitwise = 0x20 }
@{ day = "saturday"; bitwise = 0x40 }
)
foreach ($entry in $map) {
$day = $entry.day
$bitwise = $entry.bitwise
if ($raw_value -band $bitwise) {
$value_list += $day
}
}
$value = $value_list -join ","
break
}
DaysOfMonth {
$value_list = @()
$map = @(
@{ day = "1"; bitwise = 0x01 }
@{ day = "2"; bitwise = 0x02 }
@{ day = "3"; bitwise = 0x04 }
@{ day = "4"; bitwise = 0x08 }
@{ day = "5"; bitwise = 0x10 }
@{ day = "6"; bitwise = 0x20 }
@{ day = "7"; bitwise = 0x40 }
@{ day = "8"; bitwise = 0x80 }
@{ day = "9"; bitwise = 0x100 }
@{ day = "10"; bitwise = 0x200 }
@{ day = "11"; bitwise = 0x400 }
@{ day = "12"; bitwise = 0x800 }
@{ day = "13"; bitwise = 0x1000 }
@{ day = "14"; bitwise = 0x2000 }
@{ day = "15"; bitwise = 0x4000 }
@{ day = "16"; bitwise = 0x8000 }
@{ day = "17"; bitwise = 0x10000 }
@{ day = "18"; bitwise = 0x20000 }
@{ day = "19"; bitwise = 0x40000 }
@{ day = "20"; bitwise = 0x80000 }
@{ day = "21"; bitwise = 0x100000 }
@{ day = "22"; bitwise = 0x200000 }
@{ day = "23"; bitwise = 0x400000 }
@{ day = "24"; bitwise = 0x800000 }
@{ day = "25"; bitwise = 0x1000000 }
@{ day = "26"; bitwise = 0x2000000 }
@{ day = "27"; bitwise = 0x4000000 }
@{ day = "28"; bitwise = 0x8000000 }
@{ day = "29"; bitwise = 0x10000000 }
@{ day = "30"; bitwise = 0x20000000 }
@{ day = "31"; bitwise = 0x40000000 }
)
foreach ($entry in $map) {
$day = $entry.day
$bitwise = $entry.bitwise
if ($raw_value -band $bitwise) {
$value_list += $day
}
}
$value = $value_list -join ","
break
}
WeeksOfMonth {
$value_list = @()
$map = @(
@{ week = "1"; bitwise = 0x01 }
@{ week = "2"; bitwise = 0x02 }
@{ week = "3"; bitwise = 0x04 }
@{ week = "4"; bitwise = 0x04 }
)
foreach ($entry in $map) {
$week = $entry.week
$bitwise = $entry.bitwise
if ($raw_value -band $bitwise) {
$value_list += $week
}
}
$value = $value_list -join ","
break
}
MonthsOfYear {
$value_list = @()
$map = @(
@{ month = "january"; bitwise = 0x01 }
@{ month = "february"; bitwise = 0x02 }
@{ month = "march"; bitwise = 0x04 }
@{ month = "april"; bitwise = 0x08 }
@{ month = "may"; bitwise = 0x10 }
@{ month = "june"; bitwise = 0x20 }
@{ month = "july"; bitwise = 0x40 }
@{ month = "august"; bitwise = 0x80 }
@{ month = "september"; bitwise = 0x100 }
@{ month = "october"; bitwise = 0x200 }
@{ month = "november"; bitwise = 0x400 }
@{ month = "december"; bitwise = 0x800 }
)
foreach ($entry in $map) {
$month = $entry.month
$bitwise = $entry.bitwise
if ($raw_value -band $bitwise) {
$value_list += $month
}
}
$value = $value_list -join ","
break
}
Type {
if ($task_property -eq "actions") {
$value = [Enum]::ToObject([TASK_ACTION_TYPE], $raw_value).ToString()
} elseif ($task_property -eq "triggers") {
$value = [Enum]::ToObject([TASK_TRIGGER_TYPE2], $raw_value).ToString()
}
break
}
RunLevel {
$value = [Enum]::ToObject([TASK_RUN_LEVEL], $raw_value).ToString()
break
}
LogonType {
$value = [Enum]::ToObject([TASK_LOGON_TYPE], $raw_value).ToString()
break
}
UserId {
$sid = Convert-ToSID -account_name $raw_value
$value = Convert-FromSid -sid $sid
}
GroupId {
$sid = Convert-ToSID -account_name $raw_value
$value = Convert-FromSid -sid $sid
}
default {
$value = $raw_value
break
}
}
return ,$value
}
$service = New-Object -ComObject Schedule.Service
try {
$service.Connect()
} catch {
Fail-Json -obj $result -message "failed to connect to the task scheduler service: $($_.Exception.Message)"
}
try {
$task_folder = $service.GetFolder($path)
$result.folder_exists = $true
} catch {
$result.folder_exists = $false
$task_folder = $null
}
$folder_tasks = $task_folder.GetTasks(1)
$folder_task_names = @()
$folder_task_count = 0
$task = $null
for ($i = 1; $i -le $folder_tasks.Count; $i++) {
$task_name = $folder_tasks.Item($i).Name
$folder_task_names += $task_name
$folder_task_count += 1
if ($name -ne $null -and $task_name -eq $name) {
$task = $folder_tasks.Item($i)
}
}
$result.folder_task_names = $folder_task_names
$result.folder_task_count = $folder_task_count
if ($name -ne $null) {
if ($task -ne $null) {
$result.task_exists = $true
# task state
$result.state = @{
last_run_time = (Get-Date $task.LastRunTime -Format s)
last_task_result = $task.LastTaskResult
next_run_time = (Get-Date $task.NextRunTime -Format s)
number_of_missed_runs = $task.NumberOfMissedRuns
status = [Enum]::ToObject([TASK_STATE], $task.State).ToString()
}
# task definition
$task_definition = $task.Definition
$ignored_properties = @("XmlText")
$properties = @("principal", "registration_info", "settings")
$collection_properties = @("actions", "triggers")
foreach ($property in $properties) {
$property_name = $property -replace "_"
$result.$property = @{}
$values = $task_definition.$property_name
Get-Member -InputObject $values -MemberType Property | % {
if ($_.Name -notin $ignored_properties) {
$result.$property.$($_.Name) = (Get-PropertyValue -task_property $property -com $values -property $_.Name)
}
}
}
foreach ($property in $collection_properties) {
$result.$property = @()
$collection = $task_definition.$property
$collection_count = $collection.Count
for ($i = 1; $i -le $collection_count; $i++) {
$item = $collection.Item($i)
$item_info = @{}
Get-Member -InputObject $item -MemberType Property | % {
if ($_.Name -notin $ignored_properties) {
$item_info.$($_.Name) = (Get-PropertyValue -task_property $property -com $item -property $_.Name)
}
}
$result.$property += $item_info
}
}
} else {
$result.task_exists = $false
}
}
$result = Convert-DictToSnakeCase -dict $result
Exit-Json -obj $result

View file

@ -0,0 +1,367 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
# this is a windows documentation stub. actual code lives in the .ps1
# file of the same name
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = r'''
---
module: win_scheduled_task_stat
version_added: "2.5"
short_description: Returns information about a Windows Scheduled Task
description:
- Will return whether the folder and task exists.
- Returns the names of tasks in the folder specified.
- If C(name) is set and exists, will return information on the task itself.
- Use M(win_scheduled_task) to configure a scheduled task.
options:
path:
description: The folder path where the task lives.
default: \
name:
description: The name of the scheduled task to get information for.
author:
- Jordan Borean (@jborean93)
'''
EXAMPLES = r'''
- name: get information about a folder
win_scheduled_task_stat:
path: \folder name
register: task_folder_stat
- name: get information about a task in the root folder
win_scheduled_task_stat:
name: task name
register: task_stat
- name: get information about a task in a custom folder
win_scheduled_task_stat:
path: \folder name
name: task name
register: task_stat
'''
RETURN = r'''
actions:
description: A list of actions.
returned: name is specified and task exists
type: list
sample: [
{
"Arguments": "/c echo hi",
"Id": null,
"Path": "cmd.exe",
"Type": "TASK_ACTION_EXEC",
"WorkingDirectory": null
}
]
folder_exists:
description: Whether the folder set at path exists.
returned: always
type: boolean
sample: True
folder_task_count:
description: The number of tasks that exist in the folder.
returned: always
type: int
sample: 2
folder_task_names:
description: A list of tasks that exist in the folder.
returned: always
type: list
sample: [ 'Task 1', 'Task 2' ]
principal:
description: Details on the principal configured to run the task.
returned: name is specified and task exists
type: complex
contains:
display_name:
description: The name of the user/group that is displayed in the Task
Scheduler UI.
returned: ''
type: str
sample: Administrator
group_id:
description: The group that will run the task.
returned: ''
type: str
sample: BUILTIN\Administrators
id:
description: The ID for the principal.
returned: ''
type: str
sample: Author
logon_type:
description: The logon method that the task will run with.
returned: ''
type: str
sample: TASK_LOGON_INTERACTIVE_TOKEN
run_level:
description: The level of user rights used to run the task.
returned: ''
type: str
sample: TASK_RUNLEVEL_LUA
user_id:
description: The user that will run the task.
returned: ''
type: str
sample: SERVER\Administrator
registration_info:
description: Details on the task registration info.
returned: name is specified and task exists
type: complex
contains:
author:
description: The author os the task.
returned: ''
type: str
sample: SERVER\Administrator
date:
description: The date when the task was register.
returned: ''
type: str
sample: '2017-01-01T10:00:00'
description:
description: The description of the task.
returned: ''
type: str
sample: task description
documentation:
description: The documentation of the task.
returned: ''
type: str
sample: task documentation
security_descriptor:
description: The security descriptor of the task.
returned: ''
type: str
sample: security descriptor
source:
description: The source of the task.
returned: ''
type: str
sample: source
uri:
description: The URI/path of the task.
returned: ''
type: str
sample: \task\task name
version:
description: The version of the task.
returned: ''
type: str
sample: 1.0
settings:
description: Details on the task settings.
returned: name is specified and task exists
type: complex
contains:
allow_demand_start:
description: Whether the task can be started by using either the Run
command of the Context menu.
returned: ''
type: bool
sample: True
allow_hard_terminate:
description: Whether the task can terminated by using TerminateProcess.
returned: ''
type: bool
sample: True
compatibility:
description: The compatibility level of the task
returned: ''
type: int
sample: 2
delete_expired_task_after:
description: The amount of time the Task Scheduler will wait before
deleting the task after it expires.
returned: ''
type: str
sample: PT10M
disallow_start_if_on_batteries:
description: Whether the task will not be started if the computer is
running on battery power.
returned: ''
type: bool
sample: False
disallow_start_on_remote_app_session:
description: Whether the task will not be started when in a remote app
session.
returned: ''
type: bool
sample: True
enabled:
description: Whether the task is enabled.
returned: ''
type: bool
sample: True
execution_time_limit:
description: The amount of time allowed to complete the task.
returned: ''
type: str
sample: PT72H
hidden:
description: Whether the task is hidden in the UI.
returned: ''
type: bool
sample: False
idle_settings:
description: The idle settings of the task.
returned: ''
type: dictionary
sample: {
"idle_settings": "PT1H"
}
maintenance_settings:
description: The maintenance settings of the task.
returned: ''
type: str
sample: null
mulitple_instances:
description: Indicates the behaviour when starting a task that is already
running.
returned: ''
type: int
sample: 2
network_settings:
description: The network settings of the task.
returned: ''
type: dictionary
sample: {
"network_settings": null
}
priority:
description: The priority level of the task.
returned: ''
type: int
sample: 7
restart_count:
description: The number of times that the task will attempt to restart
on failures.
returned: ''
type: int
sample: 0
restart_interval:
description: How long the Task Scheduler will attempt to restart the
task.
returned: ''
type: str
sample: PT15M
run_only_id_idle:
description: Whether the task will run if the computer is in an idle
state.
returned: ''
type: bool
sample: True
run_only_if_network_available:
description: Whether the task will run only when a network is available.
returned: ''
type: bool
sample: False
start_when_available:
description: Whether the task can start at any time after its scheduled
time has passed.
returned: ''
type: bool
sample: False
stop_if_going_on_batteries:
description: Whether the task will be stopped if the computer begins to
run on battery power.
returned: ''
type: bool
sample: True
use_unified_scheduling_engine:
description: Whether the task will use the unifed scheduling engine.
returned: ''
type: bool
sample: False
volatile:
description: Whether thet ask is volatile.
returned: ''
type: bool
sample: False
wake_to_run:
description: Whether the task will wake the computer when it is time to
run the task.
returned: ''
type: bool
sample: False
state:
description: Details on the state of the task
returned: name is specified and task exists
type: complex
contains:
last_run_time:
description: The time the registered task was last run.
returned: ''
type: str
sample: '2017-09-20T20:50:00'
last_task_result:
description: The results that were returned the last time the task was
run.
returned: ''
type: int
sample: 267009
next_run_time:
description: The time when the task is next scheduled to run.
returned: ''
type: str
sample: '2017-09-20T22:50:00'
number_of_missed_runs:
description: The number of times a task has missed a scheduled run.
returned: ''
type: int
sample: 1
status:
description: The status of the task, whether it is running, stopped, etc.
returned: ''
type: str
sample: TASK_STATE_RUNNING
task_exists:
description: Whether the task at the folder exists.
returned: name is specified
type: boolean
sample: True
triggers:
description: A list of triggers.
returned: name is specified and task exists
type: list
sample: [
{
"delay": "PT15M",
"enabled": true,
"end_boundary": null,
"execution_time_limit": null,
"id": null,
"repetition": {
"repetition": false
},
"start_boundary": null,
"type": "TASK_TRIGGER_BOOT"
},
{
"days_of_month": "5,15,30",
"enabled": true,
"end_boundary": null,
"execution_time_limit": null,
"id": null,
"months_of_year": "june,december",
"random_delay": null,
"repetition": {
"repetition": false
},
"run_on_last_day_of_month": true,
"start_boundary": "2017-09-20T03:44:38",
"type": "TASK_TRIGGER_MONTHLY"
}
]
'''