1 #!powershell
2 
3 # Copyright: (c) 2017, Ansible Project
4 # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
5 
6 #Requires -Module Ansible.ModuleUtils.CamelConversion
7 #Requires -Module Ansible.ModuleUtils.Legacy
8 #Requires -Module Ansible.ModuleUtils.SID
9 
10 $params = Parse-Args -arguments $args
11 $_remote_tmp = Get-AnsibleParam $params "_ansible_remote_tmp" -type "path" -default $env:TMP
12 
13 $path = Get-AnsibleParam -obj $params -name "path" -type "str" -default "\"
14 $name = Get-AnsibleParam -obj $params -name "name" -type "str"
15 
16 $result = @{
17     changed = $false
18 }
19 
20 $task_enums = @"
21 public enum TASK_ACTION_TYPE
22 {
23     TASK_ACTION_EXEC          = 0,
24     // The below are not supported and are only kept for documentation purposes
25     TASK_ACTION_COM_HANDLER   = 5,
26     TASK_ACTION_SEND_EMAIL    = 6,
27     TASK_ACTION_SHOW_MESSAGE  = 7
28 }
29 
30 public enum TASK_LOGON_TYPE
31 {
32     TASK_LOGON_NONE                           = 0,
33     TASK_LOGON_PASSWORD                       = 1,
34     TASK_LOGON_S4U                            = 2,
35     TASK_LOGON_INTERACTIVE_TOKEN              = 3,
36     TASK_LOGON_GROUP                          = 4,
37     TASK_LOGON_SERVICE_ACCOUNT                = 5,
38     TASK_LOGON_INTERACTIVE_TOKEN_OR_PASSWORD  = 6
39 }
40 
41 public enum TASK_RUN_LEVEL
42 {
43     TASK_RUNLEVEL_LUA      = 0,
44     TASK_RUNLEVEL_HIGHEST  = 1
45 }
46 
47 public enum TASK_STATE
48 {
49     TASK_STATE_UNKNOWN   = 0,
50     TASK_STATE_DISABLED  = 1,
51     TASK_STATE_QUEUED    = 2,
52     TASK_STATE_READY     = 3,
53     TASK_STATE_RUNNING   = 4
54 }
55 
56 public enum TASK_TRIGGER_TYPE2
57 {
58     TASK_TRIGGER_EVENT                 = 0,
59     TASK_TRIGGER_TIME                  = 1,
60     TASK_TRIGGER_DAILY                 = 2,
61     TASK_TRIGGER_WEEKLY                = 3,
62     TASK_TRIGGER_MONTHLY               = 4,
63     TASK_TRIGGER_MONTHLYDOW            = 5,
64     TASK_TRIGGER_IDLE                  = 6,
65     TASK_TRIGGER_REGISTRATION          = 7,
66     TASK_TRIGGER_BOOT                  = 8,
67     TASK_TRIGGER_LOGON                 = 9,
68     TASK_TRIGGER_SESSION_STATE_CHANGE  = 11
69 }
70 "@
71 
72 $original_tmp = $env:TMP
73 $env:TMP = $_remote_tmp
74 Add-Type -TypeDefinition $task_enums
75 $env:TMP = $original_tmp
76 
Get-PropertyValue($task_property, $com, $property)77 Function Get-PropertyValue($task_property, $com, $property) {
78     $raw_value = $com.$property
79 
80     if ($null -eq $raw_value) {
81         return $null
82     } elseif ($raw_value.GetType().Name -eq "__ComObject") {
83         $com_values = @{}
84         Get-Member -InputObject $raw_value -MemberType Property | ForEach-Object {
85             $com_value = Get-PropertyValue -task_property $property -com $raw_value -property $_.Name
86             $com_values.$($_.Name) = $com_value
87         }
88 
89         return ,$com_values
90     }
91 
92     switch ($property) {
93         DaysOfWeek {
94             $value_list = @()
95             $map = @(
96                 @{ day = "sunday"; bitwise = 0x01 }
97                 @{ day = "monday"; bitwise = 0x02 }
98                 @{ day = "tuesday"; bitwise = 0x04 }
99                 @{ day = "wednesday"; bitwise = 0x08 }
100                 @{ day = "thursday"; bitwise = 0x10 }
101                 @{ day = "friday"; bitwise = 0x20 }
102                 @{ day = "saturday"; bitwise = 0x40 }
103             )
104             foreach ($entry in $map) {
105                 $day = $entry.day
106                 $bitwise = $entry.bitwise
107                 if ($raw_value -band $bitwise) {
108                     $value_list += $day
109                 }
110             }
111 
112             $value = $value_list -join ","
113             break
114         }
115         DaysOfMonth {
116             $value_list = @()
117             $map = @(
118                 @{ day = "1"; bitwise = 0x01 }
119                 @{ day = "2"; bitwise = 0x02 }
120                 @{ day = "3"; bitwise = 0x04 }
121                 @{ day = "4"; bitwise = 0x08 }
122                 @{ day = "5"; bitwise = 0x10 }
123                 @{ day = "6"; bitwise = 0x20 }
124                 @{ day = "7"; bitwise = 0x40 }
125                 @{ day = "8"; bitwise = 0x80 }
126                 @{ day = "9"; bitwise = 0x100 }
127                 @{ day = "10"; bitwise = 0x200 }
128                 @{ day = "11"; bitwise = 0x400 }
129                 @{ day = "12"; bitwise = 0x800 }
130                 @{ day = "13"; bitwise = 0x1000 }
131                 @{ day = "14"; bitwise = 0x2000 }
132                 @{ day = "15"; bitwise = 0x4000 }
133                 @{ day = "16"; bitwise = 0x8000 }
134                 @{ day = "17"; bitwise = 0x10000 }
135                 @{ day = "18"; bitwise = 0x20000 }
136                 @{ day = "19"; bitwise = 0x40000 }
137                 @{ day = "20"; bitwise = 0x80000 }
138                 @{ day = "21"; bitwise = 0x100000 }
139                 @{ day = "22"; bitwise = 0x200000 }
140                 @{ day = "23"; bitwise = 0x400000 }
141                 @{ day = "24"; bitwise = 0x800000 }
142                 @{ day = "25"; bitwise = 0x1000000 }
143                 @{ day = "26"; bitwise = 0x2000000 }
144                 @{ day = "27"; bitwise = 0x4000000 }
145                 @{ day = "28"; bitwise = 0x8000000 }
146                 @{ day = "29"; bitwise = 0x10000000 }
147                 @{ day = "30"; bitwise = 0x20000000 }
148                 @{ day = "31"; bitwise = 0x40000000 }
149             )
150 
151             foreach ($entry in $map) {
152                 $day = $entry.day
153                 $bitwise = $entry.bitwise
154                 if ($raw_value -band $bitwise) {
155                     $value_list += $day
156                 }
157             }
158 
159             $value = $value_list -join ","
160             break
161         }
162         WeeksOfMonth {
163             $value_list = @()
164             $map = @(
165                 @{ week = "1"; bitwise = 0x01 }
166                 @{ week = "2"; bitwise = 0x02 }
167                 @{ week = "3"; bitwise = 0x04 }
168                 @{ week = "4"; bitwise = 0x04 }
169             )
170 
171             foreach ($entry in $map) {
172                 $week = $entry.week
173                 $bitwise = $entry.bitwise
174                 if ($raw_value -band $bitwise) {
175                     $value_list += $week
176                 }
177             }
178 
179             $value = $value_list -join ","
180             break
181         }
182         MonthsOfYear {
183             $value_list = @()
184             $map = @(
185                 @{ month = "january"; bitwise = 0x01 }
186                 @{ month = "february"; bitwise = 0x02 }
187                 @{ month = "march"; bitwise = 0x04 }
188                 @{ month = "april"; bitwise = 0x08 }
189                 @{ month = "may"; bitwise = 0x10 }
190                 @{ month = "june"; bitwise = 0x20 }
191                 @{ month = "july"; bitwise = 0x40 }
192                 @{ month = "august"; bitwise = 0x80 }
193                 @{ month = "september"; bitwise = 0x100 }
194                 @{ month = "october"; bitwise = 0x200 }
195                 @{ month = "november"; bitwise = 0x400 }
196                 @{ month = "december"; bitwise = 0x800 }
197             )
198 
199             foreach ($entry in $map) {
200                 $month = $entry.month
201                 $bitwise = $entry.bitwise
202                 if ($raw_value -band $bitwise) {
203                     $value_list += $month
204                 }
205             }
206 
207             $value = $value_list -join ","
208             break
209         }
210         Type {
211             if ($task_property -eq "actions") {
212                 $value = [Enum]::ToObject([TASK_ACTION_TYPE], $raw_value).ToString()
213             } elseif ($task_property -eq "triggers") {
214                 $value = [Enum]::ToObject([TASK_TRIGGER_TYPE2], $raw_value).ToString()
215             }
216             break
217         }
218         RunLevel {
219             $value = [Enum]::ToObject([TASK_RUN_LEVEL], $raw_value).ToString()
220             break
221         }
222         LogonType {
223             $value = [Enum]::ToObject([TASK_LOGON_TYPE], $raw_value).ToString()
224             break
225         }
226         UserId {
227             $sid = Convert-ToSID -account_name $raw_value
228             $value = Convert-FromSid -sid $sid
229         }
230         GroupId {
231             $sid = Convert-ToSID -account_name $raw_value
232             $value = Convert-FromSid -sid $sid
233         }
234         default {
235             $value = $raw_value
236             break
237         }
238     }
239 
240     return ,$value
241 }
242 
243 $service = New-Object -ComObject Schedule.Service
244 try {
245     $service.Connect()
246 } catch {
247     Fail-Json -obj $result -message "failed to connect to the task scheduler service: $($_.Exception.Message)"
248 }
249 
250 try {
251     $task_folder = $service.GetFolder($path)
252     $result.folder_exists = $true
253 } catch {
254     $result.folder_exists = $false
255     if ($null -ne $name) {
256         $result.task_exists = $false
257     }
258     Exit-Json -obj $result
259 }
260 
261 $folder_tasks = $task_folder.GetTasks(1)
262 $folder_task_names = @()
263 $folder_task_count = 0
264 $task = $null
265 for ($i = 1; $i -le $folder_tasks.Count; $i++) {
266     $task_name = $folder_tasks.Item($i).Name
267     $folder_task_names += $task_name
268     $folder_task_count += 1
269 
270     if ($null -ne $name -and $task_name -eq $name) {
271         $task = $folder_tasks.Item($i)
272     }
273 }
274 $result.folder_task_names = $folder_task_names
275 $result.folder_task_count = $folder_task_count
276 
277 if ($null -ne $name) {
278     if ($null -ne $task) {
279         $result.task_exists = $true
280 
281         # task state
282         $result.state = @{
283             last_run_time = (Get-Date $task.LastRunTime -Format s)
284             last_task_result = $task.LastTaskResult
285             next_run_time = (Get-Date $task.NextRunTime -Format s)
286             number_of_missed_runs = $task.NumberOfMissedRuns
287             status = [Enum]::ToObject([TASK_STATE], $task.State).ToString()
288         }
289 
290         # task definition
291         $task_definition = $task.Definition
292         $ignored_properties = @("XmlText")
293         $properties = @("principal", "registration_info", "settings")
294         $collection_properties = @("actions", "triggers")
295 
296         foreach ($property in $properties) {
297             $property_name = $property -replace "_"
298             $result.$property = @{}
299             $values = $task_definition.$property_name
300             Get-Member -InputObject $values -MemberType Property | ForEach-Object {
301                 if ($_.Name -notin $ignored_properties) {
302                     $result.$property.$($_.Name) = (Get-PropertyValue -task_property $property -com $values -property $_.Name)
303                 }
304             }
305         }
306 
307         foreach ($property in $collection_properties) {
308             $result.$property = @()
309             $collection = $task_definition.$property
310             $collection_count = $collection.Count
311             for ($i = 1; $i -le $collection_count; $i++) {
312                 $item = $collection.Item($i)
313                 $item_info = @{}
314 
315                 Get-Member -InputObject $item -MemberType Property | ForEach-Object {
316                     if ($_.Name -notin $ignored_properties) {
317                         $item_info.$($_.Name) = (Get-PropertyValue -task_property $property -com $item -property $_.Name)
318                     }
319                 }
320                 $result.$property += $item_info
321             }
322         }
323     } else {
324         $result.task_exists = $false
325     }
326 }
327 
328 $result = Convert-DictToSnakeCase -dict $result
329 
330 Exit-Json -obj $result
331