win32-taskscheduler 1.0.10 → 1.0.12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -7
- data/VERSION +1 -1
- data/examples/taskscheduler_example.rb +14 -16
- data/lib/win32/taskscheduler.rb +234 -150
- data/lib/win32/taskscheduler/version.rb +1 -1
- data/lib/win32/windows/constants.rb +11 -8
- data/lib/win32/windows/helper.rb +5 -1
- data/lib/win32/windows/sid.rb +128 -0
- data/spec/functional/win32/taskschedular_spec.rb +88 -34
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5b6d6ad467e4dd3518af4776d1937f9227afbc42bf743c3f3b09480141e08e15
|
4
|
+
data.tar.gz: 2a3a9d694c22b5734e30c50fe50142af6b23e6d467c8e38e33ee48bba3a15952
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e5ca12f5424d5f790107a1af5ff8838e7931d846cdece3959627c0500a34ff2bcdae1fa749f253a89f4b523065ca27b15f1e629dc11ad586a990854cfbcb2a83
|
7
|
+
data.tar.gz: c423125d42002ae09d4bc1fab148004a325e399cbdeb5bb48fb6210f1f3f5af510a4ecd9f0345fd8ec1e4291905c214d2e8d58eb261cd5b7e791d2b3c59c9c49
|
data/CHANGELOG.md
CHANGED
@@ -4,21 +4,28 @@ Note: this log contains only changes from win32-taskscheduler release 0.4.0 and
|
|
4
4
|
-- it does not contain the changes from prior releases. To view change history
|
5
5
|
prior to release 0.4.0, please visit the [source repository](https://github.com/chef/win32-taskscheduler/commits).
|
6
6
|
|
7
|
-
<!-- latest_release 1.0.
|
8
|
-
## [win32-taskscheduler-1.0.
|
7
|
+
<!-- latest_release 1.0.12 -->
|
8
|
+
## [win32-taskscheduler-1.0.12](https://github.com/chef/win32-taskscheduler/tree/win32-taskscheduler-1.0.12) (2018-10-11)
|
9
9
|
|
10
10
|
#### Merged Pull Requests
|
11
|
-
-
|
11
|
+
- Fixing user registration at Non English version of windows [#69](https://github.com/chef/win32-taskscheduler/pull/69) ([Nimesh-Msys](https://github.com/Nimesh-Msys))
|
12
12
|
<!-- latest_release -->
|
13
13
|
|
14
|
-
<!-- release_rollup since=1.0.
|
15
|
-
### Changes since 1.0.
|
14
|
+
<!-- release_rollup since=1.0.10 -->
|
15
|
+
### Changes since 1.0.10 release
|
16
16
|
|
17
17
|
#### Merged Pull Requests
|
18
|
-
-
|
18
|
+
- Fixing user registration at Non English version of windows [#69](https://github.com/chef/win32-taskscheduler/pull/69) ([Nimesh-Msys](https://github.com/Nimesh-Msys)) <!-- 1.0.12 -->
|
19
|
+
- Refactored configure_settings [#67](https://github.com/chef/win32-taskscheduler/pull/67) ([btm](https://github.com/btm)) <!-- 1.0.11 -->
|
19
20
|
<!-- release_rollup -->
|
20
21
|
|
21
22
|
<!-- latest_stable_release -->
|
23
|
+
## [win32-taskscheduler-1.0.10](https://github.com/chef/win32-taskscheduler/tree/win32-taskscheduler-1.0.10) (2018-07-24)
|
24
|
+
|
25
|
+
#### Merged Pull Requests
|
26
|
+
- Fix exists? method breaking task full path search [#62](https://github.com/chef/win32-taskscheduler/pull/62) ([Vasu1105](https://github.com/Vasu1105))
|
27
|
+
<!-- latest_stable_release -->
|
28
|
+
|
22
29
|
## [win32-taskscheduler-1.0.9](https://github.com/chef/win32-taskscheduler/tree/win32-taskscheduler-1.0.9) (2018-07-23)
|
23
30
|
|
24
31
|
#### Merged Pull Requests
|
@@ -29,7 +36,6 @@ prior to release 0.4.0, please visit the [source repository](https://github.com/
|
|
29
36
|
- [MSYS-827] Add functional test cases [#58](https://github.com/chef/win32-taskscheduler/pull/58) ([Nimesh-Msys](https://github.com/Nimesh-Msys))
|
30
37
|
- Add DisallowStartIfOnBatteries and StopIfGoingOnBatteries task configs [#61](https://github.com/chef/win32-taskscheduler/pull/61) ([dheerajd-msys](https://github.com/dheerajd-msys))
|
31
38
|
- Fix priority should return unique value. [#60](https://github.com/chef/win32-taskscheduler/pull/60) ([Vasu1105](https://github.com/Vasu1105))
|
32
|
-
<!-- latest_stable_release -->
|
33
39
|
|
34
40
|
## [win32-taskscheduler-1.0.2](https://github.com/chef/win32-taskscheduler/tree/win32-taskscheduler-1.0.2) (2018-06-13)
|
35
41
|
- Fix for exists? method returning false for task without full path. [#43](https://github.com/chef/win32-taskscheduler/pull/43)([#Vasu1105](https://github.com/Vasu1105))
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0.
|
1
|
+
1.0.12
|
@@ -6,30 +6,29 @@
|
|
6
6
|
#
|
7
7
|
# Modify as you see fit.
|
8
8
|
#######################################################################
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
9
|
+
require "win32/taskscheduler"
|
10
|
+
require "fileutils"
|
11
|
+
require "pp"
|
12
12
|
include Win32
|
13
13
|
|
14
|
-
puts
|
14
|
+
puts "VERSION: " + TaskScheduler::VERSION
|
15
15
|
|
16
16
|
ts = TaskScheduler.new
|
17
17
|
|
18
18
|
trigger = {
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
19
|
+
start_year: 2009,
|
20
|
+
start_month: 4,
|
21
|
+
start_day: 11,
|
22
|
+
start_hour: 7,
|
23
|
+
start_minute: 14,
|
24
|
+
trigger_type: TaskScheduler::DAILY,
|
25
|
+
type: { "days_interval" => 1 }
|
26
26
|
}
|
27
27
|
|
28
28
|
unless ts.enum.grep(/foo/).length > 0
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
puts "Task Added"
|
29
|
+
ts.new_work_item("foo", trigger)
|
30
|
+
ts.application_name = "notepad.exe"
|
31
|
+
puts "Task Added"
|
33
32
|
end
|
34
33
|
|
35
34
|
ts.activate("foo")
|
@@ -39,7 +38,6 @@ ts.working_directory = "C:\\"
|
|
39
38
|
puts "App name: " + ts.application_name
|
40
39
|
puts "Creator: " + ts.creator
|
41
40
|
puts "Exit code: " + ts.exit_code.to_s
|
42
|
-
puts "Flags: " + ts.flags.to_s
|
43
41
|
puts "Max run time: " + ts.max_run_time.to_s
|
44
42
|
puts "Next run time: " + ts.next_run_time.to_s
|
45
43
|
puts "Parameters: " + ts.parameters
|
data/lib/win32/taskscheduler.rb
CHANGED
@@ -329,36 +329,26 @@ module Win32
|
|
329
329
|
# Sets the +user+ and +password+ for the given task. If the user and
|
330
330
|
# password are set properly then true is returned.
|
331
331
|
# throws TypeError if password is not provided for other than system users
|
332
|
-
def set_account_information(
|
333
|
-
|
334
|
-
unless SYSTEM_USERS.include?(user.upcase)
|
335
|
-
raise TypeError unless password.is_a?(String)
|
336
|
-
end
|
332
|
+
def set_account_information(user_id, password)
|
333
|
+
check_credential_requirements(user_id, password)
|
337
334
|
check_for_active_task
|
338
|
-
|
339
335
|
@password = password
|
340
|
-
|
341
|
-
begin
|
342
|
-
@task = @root.RegisterTaskDefinition(
|
343
|
-
@task.Path,
|
344
|
-
@task.Definition,
|
345
|
-
TASK_CREATE_OR_UPDATE,
|
346
|
-
user,
|
347
|
-
password,
|
348
|
-
password ? TASK_LOGON_PASSWORD : TASK_LOGON_SERVICE_ACCOUNT
|
349
|
-
)
|
350
|
-
rescue WIN32OLERuntimeError => err
|
351
|
-
raise Error, ole_error('RegisterTaskDefinition', err)
|
352
|
-
end
|
353
|
-
|
336
|
+
register_task_definition(@task.Definition, @task.Path, user_id, password)
|
354
337
|
true
|
355
338
|
end
|
356
339
|
|
357
|
-
# Returns the user associated with the task or nil if no
|
358
|
-
#
|
340
|
+
# Returns the user or group associated with the task or nil if no one has been associated with the task yet
|
341
|
+
#
|
342
|
+
# @return [String] user or group associated with the task
|
359
343
|
#
|
360
344
|
def account_information
|
361
|
-
@task.nil?
|
345
|
+
if @task.nil?
|
346
|
+
nil
|
347
|
+
elsif !@task.Definition.Principal.UserId.empty?
|
348
|
+
@task.Definition.Principal.UserId
|
349
|
+
else
|
350
|
+
@task.Definition.Principal.GroupId
|
351
|
+
end
|
362
352
|
end
|
363
353
|
|
364
354
|
# Returns the name of the application associated with the task. If
|
@@ -391,7 +381,7 @@ module Win32
|
|
391
381
|
action.Path = app if action.Type == 0
|
392
382
|
end
|
393
383
|
|
394
|
-
|
384
|
+
register_task_definition(definition)
|
395
385
|
|
396
386
|
app
|
397
387
|
end
|
@@ -426,7 +416,7 @@ module Win32
|
|
426
416
|
action.Arguments = param if action.Type == 0
|
427
417
|
end
|
428
418
|
|
429
|
-
|
419
|
+
register_task_definition(definition)
|
430
420
|
|
431
421
|
param
|
432
422
|
end
|
@@ -459,7 +449,7 @@ module Win32
|
|
459
449
|
action.WorkingDirectory = dir if action.Type == 0
|
460
450
|
end
|
461
451
|
|
462
|
-
|
452
|
+
register_task_definition(definition)
|
463
453
|
|
464
454
|
dir
|
465
455
|
end
|
@@ -511,7 +501,7 @@ module Win32
|
|
511
501
|
definition = @task.Definition
|
512
502
|
definition.Settings.Priority = priority
|
513
503
|
|
514
|
-
|
504
|
+
register_task_definition(definition)
|
515
505
|
|
516
506
|
priority
|
517
507
|
end
|
@@ -521,16 +511,12 @@ module Win32
|
|
521
511
|
# job should run.
|
522
512
|
#
|
523
513
|
def new_work_item(task, trigger, userinfo = { user: nil, password: nil })
|
524
|
-
raise TypeError unless userinfo.is_a?(Hash)
|
525
|
-
raise TypeError unless task.is_a?(String)
|
526
|
-
raise TypeError unless trigger.is_a?(Hash)
|
514
|
+
raise TypeError unless userinfo.is_a?(Hash) && task.is_a?(String) && trigger.is_a?(Hash)
|
527
515
|
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
end
|
533
|
-
end
|
516
|
+
# If user ID is not given, consider it as a 'SYSTEM' user
|
517
|
+
userinfo[:user] = SERVICE_ACCOUNT_USERS.first if userinfo[:user].to_s.empty?
|
518
|
+
|
519
|
+
check_credential_requirements(userinfo[:user], userinfo[:password])
|
534
520
|
|
535
521
|
taskDefinition = @service.NewTask(0)
|
536
522
|
taskDefinition.RegistrationInfo.Description = ''
|
@@ -621,18 +607,8 @@ module Win32
|
|
621
607
|
act.Path = 'cmd'
|
622
608
|
|
623
609
|
@password = userinfo[:password]
|
624
|
-
|
625
|
-
|
626
|
-
task,
|
627
|
-
taskDefinition,
|
628
|
-
TASK_CREATE_OR_UPDATE,
|
629
|
-
userinfo[:user].nil? || userinfo[:user].empty? ? 'SYSTEM': userinfo[:user],
|
630
|
-
userinfo[:password],
|
631
|
-
userinfo[:password] ? TASK_LOGON_PASSWORD : TASK_LOGON_SERVICE_ACCOUNT
|
632
|
-
)
|
633
|
-
rescue WIN32OLERuntimeError => err
|
634
|
-
raise Error, ole_error('RegisterTaskDefinition', err)
|
635
|
-
end
|
610
|
+
|
611
|
+
register_task_definition(taskDefinition, task, userinfo[:user], userinfo[:password])
|
636
612
|
|
637
613
|
@task = @root.GetTask(task)
|
638
614
|
end
|
@@ -677,7 +653,7 @@ module Win32
|
|
677
653
|
|
678
654
|
definition = @task.Definition
|
679
655
|
definition.Triggers.Remove(index)
|
680
|
-
|
656
|
+
register_task_definition(definition)
|
681
657
|
|
682
658
|
index
|
683
659
|
end
|
@@ -860,7 +836,7 @@ module Win32
|
|
860
836
|
end
|
861
837
|
end
|
862
838
|
|
863
|
-
|
839
|
+
register_task_definition(definition)
|
864
840
|
|
865
841
|
trigger
|
866
842
|
end
|
@@ -947,7 +923,7 @@ module Win32
|
|
947
923
|
trig.Delay = "PT#{trigger[:delay_duration]||0}M"
|
948
924
|
end
|
949
925
|
|
950
|
-
|
926
|
+
register_task_definition(definition)
|
951
927
|
|
952
928
|
true
|
953
929
|
end
|
@@ -1004,7 +980,7 @@ module Win32
|
|
1004
980
|
|
1005
981
|
definition = @task.Definition
|
1006
982
|
definition.RegistrationInfo.Description = comment
|
1007
|
-
|
983
|
+
register_task_definition(definition)
|
1008
984
|
|
1009
985
|
comment
|
1010
986
|
end
|
@@ -1028,7 +1004,7 @@ module Win32
|
|
1028
1004
|
|
1029
1005
|
definition = @task.Definition
|
1030
1006
|
definition.RegistrationInfo.Author = creator
|
1031
|
-
|
1007
|
+
register_task_definition(definition)
|
1032
1008
|
|
1033
1009
|
creator
|
1034
1010
|
end
|
@@ -1059,18 +1035,6 @@ module Win32
|
|
1059
1035
|
time
|
1060
1036
|
end
|
1061
1037
|
|
1062
|
-
# Returns idle settings for current active task
|
1063
|
-
#
|
1064
|
-
def idle_settings
|
1065
|
-
check_for_active_task
|
1066
|
-
idle_settings = {}
|
1067
|
-
idle_settings[:idle_duration] = @task.Definition.Settings.IdleSettings.IdleDuration
|
1068
|
-
idle_settings[:stop_on_idle_end] = @task.Definition.Settings.IdleSettings.StopOnIdleEnd
|
1069
|
-
idle_settings[:wait_timeout] = @task.Definition.Settings.IdleSettings.WaitTimeout
|
1070
|
-
idle_settings[:restart_on_idle] = @task.Definition.Settings.IdleSettings.RestartOnIdle
|
1071
|
-
idle_settings
|
1072
|
-
end
|
1073
|
-
|
1074
1038
|
# Returns the execution time limit for current active task
|
1075
1039
|
#
|
1076
1040
|
def execution_time_limit
|
@@ -1120,89 +1084,93 @@ module Win32
|
|
1120
1084
|
|
1121
1085
|
definition = @task.Definition
|
1122
1086
|
definition.Settings.ExecutionTimeLimit = limit
|
1123
|
-
|
1087
|
+
register_task_definition(definition)
|
1124
1088
|
|
1125
1089
|
max_run_time
|
1126
1090
|
end
|
1127
1091
|
|
1128
|
-
#
|
1129
|
-
# The possible options are:
|
1130
|
-
#
|
1131
|
-
# * allow_demand_start
|
1132
|
-
# * allow_hard_terminate
|
1133
|
-
# * compatibility
|
1134
|
-
# * delete_expired_task_after
|
1135
|
-
# * disallowed_start_if_on_batteries
|
1136
|
-
# * enabled
|
1137
|
-
# * execution_time_limit (or max_run_time)
|
1138
|
-
# * hidden
|
1139
|
-
# * idle_settings
|
1140
|
-
# * network_settings
|
1141
|
-
# * priority
|
1142
|
-
# * restart_count
|
1143
|
-
# * restart_interval
|
1144
|
-
# * run_only_if_idle
|
1145
|
-
# * run_only_if_network_available
|
1146
|
-
# * start_when_available
|
1147
|
-
# * stop_if_going_on_batteries
|
1148
|
-
# * wake_to_run
|
1149
|
-
# * xml_text (or xml)
|
1092
|
+
# The Idle settings of a task
|
1150
1093
|
#
|
1151
|
-
|
1152
|
-
|
1153
|
-
|
1094
|
+
# @see https://docs.microsoft.com/en-us/windows/desktop/TaskSchd/idlesettings#properties
|
1095
|
+
#
|
1096
|
+
IdleSettings = %i[idle_duration restart_on_idle stop_on_idle_end wait_timeout]
|
1097
|
+
|
1098
|
+
# Configures tasks settings
|
1099
|
+
#
|
1100
|
+
# @param [Hash] settings_hash The settings to configure a task
|
1101
|
+
# @option settings_hash [Boolean] :allow_demand_start The subject
|
1102
|
+
# @option settings_hash [Boolean] :allow_hard_terminate
|
1103
|
+
# @option settings_hash [Boolean] :disallow_start_if_on_batteries
|
1104
|
+
# @option settings_hash [Boolean] :disallow_start_on_remote_app_session
|
1105
|
+
# @option settings_hash [Boolean] :enabled
|
1106
|
+
# @option settings_hash [Boolean] :hidden
|
1107
|
+
# @option settings_hash [Boolean] :run_only_if_idle
|
1108
|
+
# @option settings_hash [Boolean] :run_only_if_network_available
|
1109
|
+
# @option settings_hash [Boolean] :start_when_available
|
1110
|
+
# @option settings_hash [Boolean] :stop_if_going_on_batteries
|
1111
|
+
# @option settings_hash [Boolean] :use_unified_scheduling_engine
|
1112
|
+
# @option settings_hash [Boolean] :volatile
|
1113
|
+
# @option settings_hash [Boolean] :wake_to_run
|
1114
|
+
# @option settings_hash [Boolean] :restart_on_idle The Idle Setting
|
1115
|
+
# @option settings_hash [Boolean] :stop_on_idle_end The Idle Setting
|
1116
|
+
# @option settings_hash [Integer] :compatibility
|
1117
|
+
# @option settings_hash [Integer] :multiple_instances
|
1118
|
+
# @option settings_hash [Integer] :priority
|
1119
|
+
# @option settings_hash [Integer] :restart_count
|
1120
|
+
# @option settings_hash [String] :delete_expired_task_after
|
1121
|
+
# @option settings_hash [String] :execution_time_limit
|
1122
|
+
# @option settings_hash [String] :restart_interval
|
1123
|
+
# @option settings_hash [String] :idle_duration The Idle Setting
|
1124
|
+
# @option settings_hash [String] :wait_timeout The Idle Setting
|
1125
|
+
#
|
1126
|
+
# @return [Hash] User input
|
1127
|
+
#
|
1128
|
+
# @see https://msdn.microsoft.com/en-us/library/windows/desktop/aa383480(v=vs.85).aspx#properties
|
1129
|
+
#
|
1130
|
+
def configure_settings(settings_hash)
|
1131
|
+
raise TypeError, "User input settings are required in hash" unless settings_hash.is_a?(Hash)
|
1154
1132
|
|
1133
|
+
check_for_active_task
|
1155
1134
|
definition = @task.Definition
|
1156
1135
|
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1160
|
-
delete_expired_task_after = hash[:delete_expired_task_after]
|
1161
|
-
disallow_start_if_on_batteries = hash[:disallow_start_if_on_batteries]
|
1162
|
-
enabled = hash[:enabled]
|
1163
|
-
execution_time_limit = "PT#{hash[:execution_time_limit] || hash[:max_run_time] || 0}M"
|
1164
|
-
hidden = hash[:hidden]
|
1165
|
-
idle_duration = "PT#{hash[:idle_duration]||0}M"
|
1166
|
-
stop_on_idle_end = hash[:stop_on_idle_end]
|
1167
|
-
wait_timeout = "PT#{hash[:wait_timeout]||0}M"
|
1168
|
-
restart_on_idle = hash[:restart_on_idle]
|
1169
|
-
network_settings = hash[:network_settings]
|
1170
|
-
priority = hash[:priority]
|
1171
|
-
restart_count = hash[:restart_count]
|
1172
|
-
restart_interval = hash[:restart_interval]
|
1173
|
-
run_only_if_idle = hash[:run_only_if_idle]
|
1174
|
-
run_only_if_network_available = hash[:run_only_if_network_available]
|
1175
|
-
start_when_available = hash[:start_when_available]
|
1176
|
-
stop_if_going_on_batteries = hash[:stop_if_going_on_batteries]
|
1177
|
-
wake_to_run = hash[:wake_to_run]
|
1178
|
-
xml_text = hash[:xml_text] || hash[:xml]
|
1136
|
+
# Check for invalid setting
|
1137
|
+
invalid_settings = settings_hash.keys - valid_settings_options
|
1138
|
+
raise TypeError, "Invalid setting passed: #{invalid_settings.join(', ')}" unless invalid_settings.empty?
|
1179
1139
|
|
1180
|
-
|
1181
|
-
|
1182
|
-
definition.Settings.Compatibility = compatibility if compatibility
|
1183
|
-
definition.Settings.DeleteExpiredTaskAfter = delete_expired_task_after if delete_expired_task_after
|
1184
|
-
definition.Settings.DisallowStartIfOnBatteries = disallow_start_if_on_batteries if !disallow_start_if_on_batteries.nil?
|
1185
|
-
definition.Settings.Enabled = enabled if enabled
|
1186
|
-
definition.Settings.ExecutionTimeLimit = execution_time_limit if execution_time_limit
|
1187
|
-
definition.Settings.Hidden = hidden if hidden
|
1188
|
-
definition.Settings.IdleSettings.IdleDuration = idle_duration if idle_duration
|
1189
|
-
definition.Settings.IdleSettings.StopOnIdleEnd = stop_on_idle_end if stop_on_idle_end
|
1190
|
-
definition.Settings.IdleSettings.WaitTimeout = wait_timeout if wait_timeout
|
1191
|
-
definition.Settings.IdleSettings.RestartOnIdle = restart_on_idle if restart_on_idle
|
1192
|
-
definition.Settings.NetworkSettings = network_settings if network_settings
|
1193
|
-
definition.Settings.Priority = priority if priority
|
1194
|
-
definition.Settings.RestartCount = restart_count if restart_count
|
1195
|
-
definition.Settings.RestartInterval = restart_interval if restart_interval
|
1196
|
-
definition.Settings.RunOnlyIfIdle = run_only_if_idle if run_only_if_idle
|
1197
|
-
definition.Settings.RunOnlyIfNetworkAvailable = run_only_if_network_available if run_only_if_network_available
|
1198
|
-
definition.Settings.StartWhenAvailable = start_when_available if start_when_available
|
1199
|
-
definition.Settings.StopIfGoingOnBatteries = stop_if_going_on_batteries if !stop_if_going_on_batteries.nil?
|
1200
|
-
definition.Settings.WakeToRun = wake_to_run if wake_to_run
|
1201
|
-
definition.Settings.XmlText = xml_text if xml_text
|
1202
|
-
|
1203
|
-
update_task_definition(definition)
|
1140
|
+
# Some modification is required in user input
|
1141
|
+
hash = settings_hash.dup
|
1204
1142
|
|
1205
|
-
|
1143
|
+
# Conversion of few settings
|
1144
|
+
hash[:execution_time_limit] = hash[:max_run_time] unless hash[:max_run_time].nil?
|
1145
|
+
%i[execution_time_limit idle_duration restart_interval wait_timeout].each do |setting|
|
1146
|
+
hash[setting] = "PT#{hash[setting]}M" unless hash[setting].nil?
|
1147
|
+
end
|
1148
|
+
|
1149
|
+
task_settings = definition.Settings
|
1150
|
+
|
1151
|
+
# Some Idle setting needs to be configured
|
1152
|
+
if IdleSettings.any? { |setting| hash.key?(setting) }
|
1153
|
+
idle_settings = task_settings.IdleSettings
|
1154
|
+
IdleSettings.each do |setting|
|
1155
|
+
unless hash[setting].nil?
|
1156
|
+
idle_settings.setproperty(camelize(setting.to_s), hash[setting])
|
1157
|
+
# This setting is not required to be configured now
|
1158
|
+
hash.delete(setting)
|
1159
|
+
end
|
1160
|
+
end
|
1161
|
+
end
|
1162
|
+
|
1163
|
+
# XML settings are not to be configured
|
1164
|
+
%i[xml_text xml].map { |x| hash.delete(x) }
|
1165
|
+
|
1166
|
+
hash.each do |setting, value|
|
1167
|
+
setting = camelize(setting.to_s)
|
1168
|
+
definition.Settings.setproperty(setting, value)
|
1169
|
+
end
|
1170
|
+
|
1171
|
+
register_task_definition(definition)
|
1172
|
+
|
1173
|
+
settings_hash
|
1206
1174
|
end
|
1207
1175
|
|
1208
1176
|
# Set registration information options. The possible options are:
|
@@ -1247,7 +1215,7 @@ module Win32
|
|
1247
1215
|
definition.RegistrationInfo.Version = version if version
|
1248
1216
|
definition.RegistrationInfo.XmlText = xml_text if xml_text
|
1249
1217
|
|
1250
|
-
|
1218
|
+
register_task_definition(definition)
|
1251
1219
|
|
1252
1220
|
hash
|
1253
1221
|
end
|
@@ -1266,7 +1234,7 @@ module Win32
|
|
1266
1234
|
definition.Principal.LogonType = principals[:logon_type] if principals[:logon_type].to_s != ""
|
1267
1235
|
definition.Principal.GroupId = principals[:group_id] if principals[:group_id].to_s != ""
|
1268
1236
|
definition.Principal.RunLevel = principals[:run_level] if principals[:run_level].to_s != ""
|
1269
|
-
|
1237
|
+
register_task_definition(definition)
|
1270
1238
|
principals
|
1271
1239
|
end
|
1272
1240
|
|
@@ -1314,8 +1282,17 @@ module Win32
|
|
1314
1282
|
symbolize_keys(settings_hash)
|
1315
1283
|
end
|
1316
1284
|
|
1285
|
+
# Returns the user or group associated with the task. If no one is associated, it returns the default user i.e., 'SYSTEM'
|
1286
|
+
#
|
1287
|
+
# @param [WIN32OLE] definition
|
1288
|
+
#
|
1289
|
+
# @return [String] user_id
|
1290
|
+
#
|
1317
1291
|
def task_user_id(definition)
|
1318
|
-
definition.Principal.UserId
|
1292
|
+
user_id = definition.Principal.UserId.to_s
|
1293
|
+
user_id = definition.Principal.GroupId.to_s if user_id.empty?
|
1294
|
+
user_id = SERVICE_ACCOUNT_USERS.first if user_id.empty?
|
1295
|
+
user_id
|
1319
1296
|
end
|
1320
1297
|
|
1321
1298
|
private
|
@@ -1325,6 +1302,16 @@ module Win32
|
|
1325
1302
|
string.gsub(/([a-z\d])([A-Z])/, '\1_\2'.freeze).downcase
|
1326
1303
|
end
|
1327
1304
|
|
1305
|
+
# Converts a snake-case string to camel-case format
|
1306
|
+
#
|
1307
|
+
# @param [String] str
|
1308
|
+
#
|
1309
|
+
# @return [String] In camel case format
|
1310
|
+
#
|
1311
|
+
def camelize(str)
|
1312
|
+
str.split('_').map(&:capitalize).join
|
1313
|
+
end
|
1314
|
+
|
1328
1315
|
# Converts all the keys of a hash to underscored-symbol format
|
1329
1316
|
def symbolize_keys(hash)
|
1330
1317
|
hash.each_with_object({}) do |(k, v), h|
|
@@ -1344,22 +1331,119 @@ module Win32
|
|
1344
1331
|
}
|
1345
1332
|
end
|
1346
1333
|
|
1334
|
+
# Configurable settings options
|
1335
|
+
#
|
1336
|
+
# @note Logically, this is summation of
|
1337
|
+
# * Settings
|
1338
|
+
# * IdleSettings - [:idle_settings]
|
1339
|
+
# * :max_run_time, :xml
|
1340
|
+
#
|
1341
|
+
# @return [Array]
|
1342
|
+
#
|
1343
|
+
def valid_settings_options
|
1344
|
+
%i[allow_demand_start allow_hard_terminate compatibility delete_expired_task_after
|
1345
|
+
disallow_start_if_on_batteries disallow_start_on_remote_app_session enabled
|
1346
|
+
execution_time_limit hidden idle_duration maintenance_settings max_run_time
|
1347
|
+
multiple_instances network_settings priority restart_count restart_interval
|
1348
|
+
restart_on_idle run_only_if_idle run_only_if_network_available
|
1349
|
+
start_when_available stop_if_going_on_batteries stop_on_idle_end
|
1350
|
+
use_unified_scheduling_engine volatile wait_timeout wake_to_run xml xml_text]
|
1351
|
+
end
|
1352
|
+
|
1347
1353
|
def check_for_active_task
|
1348
1354
|
raise Error, 'No currently active task' if @task.nil?
|
1349
1355
|
end
|
1350
1356
|
|
1351
|
-
|
1352
|
-
|
1357
|
+
# Checks if the user belongs to service accounts category
|
1358
|
+
#
|
1359
|
+
# @return [Boolean] True or False
|
1360
|
+
#
|
1361
|
+
def service_account_user?(user)
|
1362
|
+
SERVICE_ACCOUNT_USERS.include?(user.to_s.upcase)
|
1363
|
+
end
|
1364
|
+
|
1365
|
+
# Checks if the user belongs to group accounts category
|
1366
|
+
#
|
1367
|
+
# @return [Boolean] True or False
|
1368
|
+
#
|
1369
|
+
def group_user?(user)
|
1370
|
+
BUILT_IN_GROUPS.include?(user.to_s.upcase)
|
1371
|
+
end
|
1372
|
+
|
1373
|
+
# Checks if the user belongs to system users category
|
1374
|
+
#
|
1375
|
+
# @return [Boolean] True or False
|
1376
|
+
#
|
1377
|
+
def system_user?(user)
|
1378
|
+
SYSTEM_USERS.include?(user.to_s.upcase)
|
1379
|
+
end
|
1380
|
+
|
1381
|
+
# Checks whether the given set of user_id and password suits our requirements.
|
1382
|
+
#
|
1383
|
+
# Raises the error in case of any failures
|
1384
|
+
#
|
1385
|
+
# Password should be nil for System Users. For other users, it is required.
|
1386
|
+
#
|
1387
|
+
# @param [String] user_id
|
1388
|
+
# @param [String] password
|
1389
|
+
#
|
1390
|
+
def check_credential_requirements(user_id, password)
|
1391
|
+
user_id = user_id.to_s
|
1392
|
+
password = password.to_s
|
1393
|
+
# Password will be required for non-system users
|
1394
|
+
if password.empty?
|
1395
|
+
unless system_user?(user_id)
|
1396
|
+
raise Error, 'Password is required for non-system users'
|
1397
|
+
end
|
1398
|
+
else
|
1399
|
+
if system_user?(user_id)
|
1400
|
+
raise Error, 'Password is not required for system users'
|
1401
|
+
end
|
1402
|
+
end
|
1403
|
+
end
|
1404
|
+
|
1405
|
+
# Returns the applicable flag as per the given users and groups which is used while
|
1406
|
+
# RegisterTaskDefinition
|
1407
|
+
#
|
1408
|
+
# @param [String] user_id
|
1409
|
+
# @param [String] password
|
1410
|
+
#
|
1411
|
+
# @return [Integer] Logon Types
|
1412
|
+
#
|
1413
|
+
def logon_type(user_id, password)
|
1414
|
+
if service_account_user?(user_id)
|
1415
|
+
TASK_LOGON_SERVICE_ACCOUNT
|
1416
|
+
elsif group_user?(user_id)
|
1417
|
+
TASK_LOGON_GROUP
|
1418
|
+
elsif !password.to_s.empty? # Password is present
|
1419
|
+
TASK_LOGON_PASSWORD
|
1420
|
+
else
|
1421
|
+
TASK_LOGON_INTERACTIVE_TOKEN
|
1422
|
+
end
|
1423
|
+
end
|
1424
|
+
|
1425
|
+
# Uses RegisterTaskDefinition and creates or updates the task
|
1426
|
+
#
|
1427
|
+
# @param [WIN32OLE] definition
|
1428
|
+
# @param [String] path
|
1429
|
+
# @param [String] user_id
|
1430
|
+
# @param [String] password
|
1431
|
+
#
|
1432
|
+
# @return [Integer] Logon Types
|
1433
|
+
#
|
1434
|
+
def register_task_definition(definition, path = nil, user_id = nil, password = nil)
|
1435
|
+
user_id ||= task_user_id(definition)
|
1436
|
+
path ||= @task.Path
|
1353
1437
|
@task = @root.RegisterTaskDefinition(
|
1354
|
-
|
1355
|
-
definition,
|
1356
|
-
TASK_CREATE_OR_UPDATE,
|
1357
|
-
|
1358
|
-
|
1359
|
-
|
1438
|
+
path, # Path (name) of the task
|
1439
|
+
definition, # definition of the task
|
1440
|
+
TASK_CREATE_OR_UPDATE, # Equivalent to TASK_CREATE | TASK_UPDATE
|
1441
|
+
user_id,
|
1442
|
+
password,
|
1443
|
+
logon_type(user_id, password)
|
1360
1444
|
)
|
1361
1445
|
rescue WIN32OLERuntimeError => err
|
1362
|
-
method_name = caller_locations(1,1)[0].label
|
1446
|
+
method_name = caller_locations(1, 1)[0].label
|
1363
1447
|
raise Error, ole_error(method_name, err)
|
1364
1448
|
end
|
1365
1449
|
end
|
@@ -1,7 +1,11 @@
|
|
1
|
+
require_relative 'sid'
|
1
2
|
module Windows
|
2
3
|
module TaskSchedulerConstants
|
4
|
+
SERVICE_ACCOUNT_USERS = SID::SERVICE_ACCOUNT_USERS
|
3
5
|
|
4
|
-
|
6
|
+
BUILT_IN_GROUPS = SID::BUILT_IN_GROUPS
|
7
|
+
|
8
|
+
SYSTEM_USERS = SERVICE_ACCOUNT_USERS + BUILT_IN_GROUPS
|
5
9
|
|
6
10
|
# Triggers
|
7
11
|
|
@@ -192,7 +196,6 @@ module Windows
|
|
192
196
|
# Not in use; currently identical to TASK_LOGON_PASSWORD
|
193
197
|
TASK_LOGON_INTERACTIVE_TOKEN_OR_PASSWORD = 6
|
194
198
|
|
195
|
-
|
196
199
|
TASK_MAX_RUN_TIMES = 1440
|
197
200
|
TASKS_TO_RETRIEVE = 5
|
198
201
|
|
@@ -215,12 +218,12 @@ module Windows
|
|
215
218
|
BELOW_NORMAL_PRIORITY_CLASS = 7 # Or 8
|
216
219
|
IDLE_PRIORITY_CLASS = 9 # Or 10
|
217
220
|
|
218
|
-
CLSCTX_INPROC_SERVER
|
219
|
-
CLSID_CTask =
|
220
|
-
CLSID_CTaskScheduler =
|
221
|
-
IID_ITaskScheduler = [0x148BD527,0xA2AB,0x11CE,0xB1,0x1F,0x00,0xAA,0x00,0x53,0x05,0x03].pack('LSSC8')
|
222
|
-
IID_ITask = [0x148BD524,0xA2AB,0x11CE,0xB1,0x1F,0x00,0xAA,0x00,0x53,0x05,0x03].pack('LSSC8')
|
223
|
-
IID_IPersistFile = [0x0000010b,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46].pack('LSSC8')
|
221
|
+
CLSCTX_INPROC_SERVER = 0x1
|
222
|
+
CLSID_CTask = [0x148BD520, 0xA2AB, 0x11CE, 0xB1, 0x1F, 0x00, 0xAA, 0x00, 0x53, 0x05, 0x03].pack('LSSC8')
|
223
|
+
CLSID_CTaskScheduler = [0x148BD52A, 0xA2AB, 0x11CE, 0xB1, 0x1F, 0x00, 0xAA, 0x00, 0x53, 0x05, 0x03].pack('LSSC8')
|
224
|
+
IID_ITaskScheduler = [0x148BD527, 0xA2AB, 0x11CE, 0xB1, 0x1F, 0x00, 0xAA, 0x00, 0x53, 0x05, 0x03].pack('LSSC8')
|
225
|
+
IID_ITask = [0x148BD524, 0xA2AB, 0x11CE, 0xB1, 0x1F, 0x00, 0xAA, 0x00, 0x53, 0x05, 0x03].pack('LSSC8')
|
226
|
+
IID_IPersistFile = [0x0000010b, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46].pack('LSSC8')
|
224
227
|
|
225
228
|
# Days of month
|
226
229
|
|
data/lib/win32/windows/helper.rb
CHANGED
@@ -8,11 +8,15 @@ module Windows
|
|
8
8
|
FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000
|
9
9
|
FORMAT_MESSAGE_MAX_WIDTH_MASK = 0x000000FF
|
10
10
|
|
11
|
-
ffi_lib :kernel32
|
11
|
+
ffi_lib :kernel32, :advapi32
|
12
12
|
|
13
13
|
attach_function :FormatMessage, :FormatMessageA,
|
14
14
|
[:ulong, :pointer, :ulong, :ulong, :pointer, :ulong, :pointer], :ulong
|
15
15
|
|
16
|
+
attach_function :ConvertStringSidToSidW, [ :pointer, :pointer ], :bool
|
17
|
+
attach_function :LookupAccountSidW, [ :pointer, :pointer, :pointer, :pointer, :pointer, :pointer, :pointer ], :bool
|
18
|
+
attach_function :LocalFree, [ :pointer ], :pointer
|
19
|
+
|
16
20
|
def win_error(function, err=FFI.errno)
|
17
21
|
err_msg = ''
|
18
22
|
flags = FORMAT_MESSAGE_IGNORE_INSERTS |
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require_relative 'helper'
|
2
|
+
|
3
|
+
module FFI
|
4
|
+
class Pointer
|
5
|
+
def read_wstring(num_wchars = nil)
|
6
|
+
if num_wchars.nil?
|
7
|
+
# Find the length of the string
|
8
|
+
length = 0
|
9
|
+
last_char = nil
|
10
|
+
while last_char != "\000\000"
|
11
|
+
length += 1
|
12
|
+
last_char = get_bytes(0, length * 2)[-2..-1]
|
13
|
+
end
|
14
|
+
|
15
|
+
num_wchars = length
|
16
|
+
end
|
17
|
+
|
18
|
+
wide_to_utf8(get_bytes(0, num_wchars * 2))
|
19
|
+
end
|
20
|
+
|
21
|
+
def wide_to_utf8(wstring)
|
22
|
+
# ensure it is actually UTF-16LE
|
23
|
+
# Ruby likes to mark binary data as ASCII-8BIT
|
24
|
+
wstring = wstring.force_encoding('UTF-16LE')
|
25
|
+
|
26
|
+
# encode it all as UTF-8 and remove trailing CRLF and NULL characters
|
27
|
+
wstring.encode('UTF-8').strip
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class SID
|
33
|
+
extend Windows::TaskSchedulerHelper
|
34
|
+
ERROR_INSUFFICIENT_BUFFER = 122
|
35
|
+
|
36
|
+
def self.LocalSystem
|
37
|
+
from_string_sid('S-1-5-18')
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.NtLocal
|
41
|
+
from_string_sid('S-1-5-19')
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.NtNetwork
|
45
|
+
from_string_sid('S-1-5-20')
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.BuiltinAdministrators
|
49
|
+
from_string_sid('S-1-5-32-544')
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.BuiltinUsers
|
53
|
+
from_string_sid('S-1-5-32-545')
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.Guests
|
57
|
+
from_string_sid('S-1-5-32-546')
|
58
|
+
end
|
59
|
+
|
60
|
+
# Converts a string-format security identifier (SID) into a valid, functional SID
|
61
|
+
# and returns a hash with account_name and account_simple_name
|
62
|
+
# @see https://docs.microsoft.com/en-us/windows/desktop/api/sddl/nf-sddl-convertstringsidtosidw
|
63
|
+
#
|
64
|
+
def self.from_string_sid(string_sid)
|
65
|
+
result = FFI::MemoryPointer.new :pointer
|
66
|
+
unless ConvertStringSidToSidW(utf8_to_wide(string_sid), result)
|
67
|
+
raise FFI::LastError.error
|
68
|
+
end
|
69
|
+
result_pointer = result.read_pointer
|
70
|
+
domain, name, use = account(result_pointer)
|
71
|
+
LocalFree(result_pointer)
|
72
|
+
account_names(domain, name, use)
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.utf8_to_wide(ustring)
|
76
|
+
# ensure it is actually UTF-8
|
77
|
+
# Ruby likes to mark binary data as ASCII-8BIT
|
78
|
+
ustring = (ustring + '').force_encoding('UTF-8')
|
79
|
+
|
80
|
+
# ensure we have the double-null termination Windows Wide likes
|
81
|
+
ustring += "\000\000" if ustring.empty? || ustring[-1].chr != "\000"
|
82
|
+
|
83
|
+
# encode it all as UTF-16LE AKA Windows Wide Character AKA Windows Unicode
|
84
|
+
ustring.encode('UTF-16LE')
|
85
|
+
end
|
86
|
+
|
87
|
+
# Accepts a security identifier (SID) as input.
|
88
|
+
# It retrieves the name of the account for this SID and the name of the
|
89
|
+
# first domain on which this SID is found
|
90
|
+
# @see https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-lookupaccountsidw
|
91
|
+
#
|
92
|
+
def self.account(sid)
|
93
|
+
sid = sid.pointer if sid.respond_to?(:pointer)
|
94
|
+
name_size = FFI::Buffer.new(:long).write_long(0)
|
95
|
+
referenced_domain_name_size = FFI::Buffer.new(:long).write_long(0)
|
96
|
+
|
97
|
+
if LookupAccountSidW(nil, sid, nil, name_size, nil, referenced_domain_name_size, nil)
|
98
|
+
raise 'Expected ERROR_INSUFFICIENT_BUFFER from LookupAccountSid, and got no error!'
|
99
|
+
elsif FFI::LastError.error != ERROR_INSUFFICIENT_BUFFER
|
100
|
+
raise FFI::LastError.error
|
101
|
+
end
|
102
|
+
|
103
|
+
name = FFI::MemoryPointer.new :char, (name_size.read_long * 2)
|
104
|
+
referenced_domain_name = FFI::MemoryPointer.new :char, (referenced_domain_name_size.read_long * 2)
|
105
|
+
use = FFI::Buffer.new(:long).write_long(0)
|
106
|
+
unless LookupAccountSidW(nil, sid, name, name_size, referenced_domain_name, referenced_domain_name_size, use)
|
107
|
+
raise FFI::LastError.error
|
108
|
+
end
|
109
|
+
[referenced_domain_name.read_wstring(referenced_domain_name_size.read_long), name.read_wstring(name_size.read_long), use.read_long]
|
110
|
+
end
|
111
|
+
|
112
|
+
# Formats domain, name and returns a hash with
|
113
|
+
# account_name and account_simple_name
|
114
|
+
#
|
115
|
+
def self.account_names(domain, name, _use)
|
116
|
+
account_name = !domain.to_s.empty? ? "#{domain}\\#{name}" : name
|
117
|
+
account_simple_name = name
|
118
|
+
{ account_name: account_name, account_simple_name: account_simple_name }
|
119
|
+
end
|
120
|
+
|
121
|
+
SERVICE_ACCOUNT_USERS = [self.LocalSystem, self.NtLocal, self.NtNetwork].map do |user|
|
122
|
+
[user[:account_simple_name].upcase, user[:account_name].upcase]
|
123
|
+
end.flatten.freeze
|
124
|
+
|
125
|
+
BUILT_IN_GROUPS = [self.BuiltinAdministrators, self.BuiltinUsers, self.Guests].map do |user|
|
126
|
+
[user[:account_simple_name].upcase, user[:account_name].upcase]
|
127
|
+
end.flatten.freeze
|
128
|
+
end
|
@@ -53,7 +53,7 @@ RSpec.describe Win32::TaskScheduler, :windows_only do
|
|
53
53
|
expect(no_of_tasks).to eq(0)
|
54
54
|
end
|
55
55
|
|
56
|
-
it
|
56
|
+
it "Raises error when path separators(\\\) are absent" do
|
57
57
|
invalid_path = 'Foo'
|
58
58
|
expect { ts.new(@task, @trigger, invalid_path) }.to raise_error(ArgumentError)
|
59
59
|
expect(no_of_tasks).to eq(0)
|
@@ -215,9 +215,9 @@ RSpec.describe Win32::TaskScheduler, :windows_only do
|
|
215
215
|
|
216
216
|
it 'Execute(Start) the Task' do
|
217
217
|
@ts.run
|
218
|
-
expect(@ts.status).to eq('running')
|
219
|
-
|
220
|
-
|
218
|
+
expect(@ts.status).to eq('running')
|
219
|
+
.or eq('queued')
|
220
|
+
.or eq('ready') # It takes time to load sometimes
|
221
221
|
end
|
222
222
|
|
223
223
|
it 'Raises an error if task does not exists' do
|
@@ -518,20 +518,48 @@ RSpec.describe Win32::TaskScheduler, :windows_only do
|
|
518
518
|
|
519
519
|
describe '#account_information' do
|
520
520
|
before { create_task }
|
521
|
-
|
522
|
-
|
523
|
-
password
|
524
|
-
|
525
|
-
|
521
|
+
context 'Service Account Users' do
|
522
|
+
let(:service_user) { 'LOCAL SERVICE' }
|
523
|
+
let(:password) { nil }
|
524
|
+
it 'Does not require any password' do
|
525
|
+
expect(@ts.set_account_information(service_user, password)). to be_truthy
|
526
|
+
expect(@ts.account_information.upcase).to eq(service_user)
|
527
|
+
end
|
528
|
+
it 'passing account_name will display account_simple_name' do
|
529
|
+
user = 'NT AUTHORITY\LOCAL SERVICE'
|
530
|
+
expect(@ts.set_account_information(user, password)). to be_truthy
|
531
|
+
expect(@ts.account_information.upcase).to eq(service_user)
|
532
|
+
end
|
533
|
+
it 'Raises an error if password is given' do
|
534
|
+
password = 'XYZ'
|
535
|
+
expect { @ts.set_account_information(service_user, password) }. to raise_error(tasksch_err)
|
536
|
+
end
|
526
537
|
end
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
password
|
531
|
-
|
532
|
-
|
538
|
+
context 'Built in Groups' do
|
539
|
+
let(:group_user) { 'USERS' }
|
540
|
+
let(:password) { nil }
|
541
|
+
it 'Does not require any password' do
|
542
|
+
expect(@ts.set_account_information(group_user, password)). to be_truthy
|
543
|
+
expect(@ts.account_information.upcase).to eq(group_user)
|
544
|
+
end
|
545
|
+
it 'passing account_name will display account_simple_name' do
|
546
|
+
user = 'BUILTIN\USERS'
|
547
|
+
expect(@ts.set_account_information(user, password)). to be_truthy
|
548
|
+
expect(@ts.account_information.upcase).to eq(group_user)
|
549
|
+
end
|
550
|
+
it 'Raises an error if password is given' do
|
551
|
+
password = 'XYZ'
|
552
|
+
expect { @ts.set_account_information(group_user, password) }. to raise_error(tasksch_err)
|
553
|
+
end
|
554
|
+
end
|
555
|
+
context 'Non-system users' do
|
556
|
+
it 'Require a password' do
|
557
|
+
user = ENV['user']
|
558
|
+
password = nil
|
559
|
+
expect { @ts.set_account_information(user, password) }. to raise_error(tasksch_err)
|
560
|
+
expect(@ts.account_information).to include(user)
|
561
|
+
end
|
533
562
|
end
|
534
|
-
|
535
563
|
it 'Raises an error if task does not exists' do
|
536
564
|
@ts.instance_variable_set(:@task, nil)
|
537
565
|
user = 'User'
|
@@ -640,31 +668,57 @@ RSpec.describe Win32::TaskScheduler, :windows_only do
|
|
640
668
|
before { create_task }
|
641
669
|
before { stub_user }
|
642
670
|
|
671
|
+
it 'Require a hash' do
|
672
|
+
expect { @ts.configure_settings('XYZ') }. to raise_error(TypeError)
|
673
|
+
expect(@ts.configure_settings({})).to eq({})
|
674
|
+
end
|
675
|
+
|
676
|
+
it 'Raises an error if invalid setting is passed' do
|
677
|
+
expect { @ts.configure_settings(invalid: true) }. to raise_error(TypeError)
|
678
|
+
end
|
679
|
+
|
680
|
+
it 'Sets settings of the task and returns a hash' do
|
681
|
+
settings = { allow_demand_start: false,
|
682
|
+
disallow_start_if_on_batteries: false,
|
683
|
+
enabled: false,
|
684
|
+
stop_if_going_on_batteries: false }
|
685
|
+
|
686
|
+
expect(@ts.configure_settings(settings)).to eq(settings)
|
687
|
+
expect(@ts.settings).to include(settings)
|
688
|
+
end
|
689
|
+
|
643
690
|
it 'Sets idle settings of the task' do
|
644
|
-
|
645
|
-
#
|
646
|
-
settings = { idle_duration:
|
647
|
-
wait_timeout:
|
691
|
+
# It accepts time in minutes
|
692
|
+
# and returns the result in ISO8601 format
|
693
|
+
settings = { idle_duration: 11,
|
694
|
+
wait_timeout: 10,
|
648
695
|
stop_on_idle_end: true,
|
649
696
|
restart_on_idle: false }
|
650
|
-
@ts.configure_settings(settings)
|
651
|
-
expect(@ts.idle_settings).to eq(settings)
|
652
|
-
end
|
653
697
|
|
654
|
-
|
655
|
-
|
656
|
-
|
698
|
+
result_settings = { idle_duration: 'PT11M',
|
699
|
+
wait_timeout: 'PT10M',
|
700
|
+
stop_on_idle_end: true,
|
701
|
+
restart_on_idle: false }
|
702
|
+
|
657
703
|
@ts.configure_settings(settings)
|
658
|
-
expect(@ts.
|
704
|
+
expect(@ts.idle_settings).to eq(result_settings)
|
659
705
|
end
|
660
706
|
|
661
|
-
it '
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
707
|
+
it 'Set settings and idle settings of the task' do
|
708
|
+
settings = {
|
709
|
+
allow_demand_start: false,
|
710
|
+
disallow_start_if_on_batteries: false,
|
711
|
+
stop_if_going_on_batteries: false
|
712
|
+
}
|
713
|
+
|
714
|
+
idle_settings = {
|
715
|
+
stop_on_idle_end: true,
|
716
|
+
restart_on_idle: false
|
717
|
+
}
|
718
|
+
|
719
|
+
@ts.configure_settings(settings.merge(idle_settings))
|
720
|
+
expect(@ts.settings).to include(settings)
|
721
|
+
expect(@ts.idle_settings).to include(idle_settings)
|
668
722
|
end
|
669
723
|
|
670
724
|
it 'Raises an error if task does not exists' do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: win32-taskscheduler
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Park Heesob
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2018-
|
12
|
+
date: 2018-10-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ffi
|
@@ -120,6 +120,7 @@ files:
|
|
120
120
|
- lib/win32/taskscheduler/version.rb
|
121
121
|
- lib/win32/windows/constants.rb
|
122
122
|
- lib/win32/windows/helper.rb
|
123
|
+
- lib/win32/windows/sid.rb
|
123
124
|
- lib/win32/windows/time_calc_helper.rb
|
124
125
|
- spec/functional/win32/taskschedular_spec.rb
|
125
126
|
- spec/functional/win32/windows/time_calc_helper_spec.rb
|