Skip to content

Commit 550074c

Browse files
authored
Merge pull request #169 from danielboth/ScheduledTaskOnEventTrigger
ScheduledTask: Add support for event based triggers
2 parents 12f3a7e + ad01864 commit 550074c

8 files changed

Lines changed: 411 additions & 40 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
- Moved strings to localization file.
1010
- Changed the scope from Global to Script in MSFT_ScheduledTask.Integration.Tests.ps1
1111
- Changed the scope from Global to Script ComputerManagementDsc.Common.Tests.ps1
12+
- ScheduledTask:
13+
- Added support for event based triggers, implemented using the ScheduleType OnEvent
14+
fixes [Issue #167](https://github.com/PowerShell/ComputerManagementDsc/issues/167)
1215

1316
## 5.1.0.0
1417

Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/MSFT_ScheduledTask.psm1

Lines changed: 99 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,15 @@ $script:localizedData = Get-LocalizedData `
201201
.PARAMETER LogonType
202202
Specifies the security logon method that Task Scheduler uses to run the tasks that
203203
are associated with the principal. Not used in Get-TargetResource.
204+
205+
.PARAMETER EventSubscription
206+
The event subscription in a string that can be parsed as valid XML. This parameter is only
207+
valid in combination with the OnEvent Schedule Type. For the query schema please check:
208+
https://docs.microsoft.com/en-us/windows/desktop/WES/queryschema-schema
209+
210+
.PARAMETER Delay
211+
The time to wait after an event based trigger was triggered. This parameter is only
212+
valid in combination with the OnEvent Schedule Type.
204213
#>
205214
function Get-TargetResource
206215
{
@@ -234,7 +243,7 @@ function Get-TargetResource
234243

235244
[Parameter()]
236245
[System.String]
237-
[ValidateSet('Once', 'Daily', 'Weekly', 'AtStartup', 'AtLogOn')]
246+
[ValidateSet('Once', 'Daily', 'Weekly', 'AtStartup', 'AtLogOn', 'OnEvent')]
238247
$ScheduleType,
239248

240249
[Parameter()]
@@ -376,7 +385,15 @@ function Get-TargetResource
376385
[Parameter()]
377386
[ValidateSet('Group', 'Interactive', 'InteractiveOrPassword', 'None', 'Password', 'S4U', 'ServiceAccount')]
378387
[System.String]
379-
$LogonType
388+
$LogonType,
389+
390+
[Parameter()]
391+
[System.String]
392+
$EventSubscription,
393+
394+
[Parameter()]
395+
[System.String]
396+
$Delay = '00:00:00'
380397
)
381398

382399
$TaskPath = ConvertTo-NormalizedTaskPath -TaskPath $TaskPath
@@ -436,6 +453,12 @@ function Get-TargetResource
436453
break
437454
}
438455

456+
'MSFT_TaskEventTrigger'
457+
{
458+
$returnScheduleType = 'OnEvent'
459+
break
460+
}
461+
439462
default
440463
{
441464
$returnScheduleType = ''
@@ -510,6 +533,8 @@ function Get-TargetResource
510533
RunOnlyIfNetworkAvailable = $settings.RunOnlyIfNetworkAvailable
511534
RunLevel = [System.String] $task.Principal.RunLevel
512535
LogonType = [System.String] $task.Principal.LogonType
536+
EventSubscription = $trigger.Subscription
537+
Delay = ConvertTo-TimeSpanStringFromScheduledTaskString -TimeSpan $trigger.Delay
513538
}
514539
}
515540
}
@@ -665,6 +690,15 @@ function Get-TargetResource
665690
.PARAMETER LogonType
666691
Specifies the security logon method that Task Scheduler uses to run the tasks that
667692
are associated with the principal.
693+
694+
.PARAMETER EventSubscription
695+
The event subscription in a string that can be parsed as valid XML. This parameter is only
696+
valid in combination with the OnEvent Schedule Type. For the query schema please check:
697+
https://docs.microsoft.com/en-us/windows/desktop/WES/queryschema-schema
698+
699+
.PARAMETER Delay
700+
The time to wait after an event based trigger was triggered. This parameter is only
701+
valid in combination with the OnEvent Schedule Type.
668702
#>
669703
function Set-TargetResource
670704
{
@@ -697,7 +731,7 @@ function Set-TargetResource
697731

698732
[Parameter()]
699733
[System.String]
700-
[ValidateSet('Once', 'Daily', 'Weekly', 'AtStartup', 'AtLogOn')]
734+
[ValidateSet('Once', 'Daily', 'Weekly', 'AtStartup', 'AtLogOn', 'OnEvent')]
701735
$ScheduleType,
702736

703737
[Parameter()]
@@ -839,7 +873,15 @@ function Set-TargetResource
839873
[Parameter()]
840874
[ValidateSet('Group', 'Interactive', 'InteractiveOrPassword', 'None', 'Password', 'S4U', 'ServiceAccount')]
841875
[System.String]
842-
$LogonType
876+
$LogonType,
877+
878+
[Parameter()]
879+
[System.String]
880+
$EventSubscription,
881+
882+
[Parameter()]
883+
[System.String]
884+
$Delay = '00:00:00'
843885
)
844886

845887
$TaskPath = ConvertTo-NormalizedTaskPath -TaskPath $TaskPath
@@ -902,6 +944,13 @@ function Set-TargetResource
902944
-ArgumentName DaysOfWeek
903945
}
904946

947+
if ($ScheduleType -eq 'OnEvent' -and -not ([xml]$EventSubscription))
948+
{
949+
New-InvalidArgumentException `
950+
-Message ($script:localizedData.OnEventSubscriptionError) `
951+
-ArgumentName EventSubscription
952+
}
953+
905954
# Configure the action
906955
$actionParameters = @{
907956
Execute = $ActionExecutable
@@ -989,7 +1038,8 @@ function Set-TargetResource
9891038
# Configure the trigger
9901039
$triggerParameters = @{}
9911040

992-
if ($RandomDelay -gt [System.TimeSpan]::FromSeconds(0))
1041+
# A random delay is not supported when the scheduleType is set to OnEvent
1042+
if ($RandomDelay -gt [System.TimeSpan]::FromSeconds(0) -and $ScheduleType -ne 'OnEvent')
9931043
{
9941044
$triggerParameters.Add('RandomDelay', $RandomDelay)
9951045
}
@@ -1049,9 +1099,23 @@ function Set-TargetResource
10491099

10501100
break
10511101
}
1102+
1103+
'OnEvent'
1104+
{
1105+
Write-Verbose -Message ($script:localizedData.ConfigureTaskEventTrigger -f $TaskName)
1106+
1107+
$cimTriggerClass = Get-CimClass -ClassName MSFT_TaskEventTrigger -Namespace Root/Microsoft/Windows/TaskScheduler:MSFT_TaskEventTrigger
1108+
$trigger = New-CimInstance -CimClass $cimTriggerClass -ClientOnly
1109+
$trigger.Enabled = $true
1110+
$trigger.Delay = [System.Xml.XmlConvert]::ToString([timespan]$Delay)
1111+
$trigger.Subscription = $EventSubscription
1112+
}
10521113
}
10531114

1054-
$trigger = New-ScheduledTaskTrigger @triggerParameters -ErrorAction SilentlyContinue
1115+
if ($ScheduleType -ne 'OnEvent')
1116+
{
1117+
$trigger = New-ScheduledTaskTrigger @triggerParameters -ErrorAction SilentlyContinue
1118+
}
10551119

10561120
if (-not $trigger)
10571121
{
@@ -1390,6 +1454,15 @@ function Set-TargetResource
13901454
.PARAMETER LogonType
13911455
Specifies the security logon method that Task Scheduler uses to run the tasks that
13921456
are associated with the principal.
1457+
1458+
.PARAMETER EventSubscription
1459+
The event subscription in a string that can be parsed as valid XML. This parameter is only
1460+
valid in combination with the OnEvent Schedule Type. For the query schema please check:
1461+
https://docs.microsoft.com/en-us/windows/desktop/WES/queryschema-schema
1462+
1463+
.PARAMETER Delay
1464+
The time to wait after an event based trigger was triggered. This parameter is only
1465+
valid in combination with the OnEvent Schedule Type.
13931466
#>
13941467
function Test-TargetResource
13951468
{
@@ -1423,7 +1496,7 @@ function Test-TargetResource
14231496

14241497
[Parameter()]
14251498
[System.String]
1426-
[ValidateSet('Once', 'Daily', 'Weekly', 'AtStartup', 'AtLogOn')]
1499+
[ValidateSet('Once', 'Daily', 'Weekly', 'AtStartup', 'AtLogOn', 'OnEvent')]
14271500
$ScheduleType,
14281501

14291502
[Parameter()]
@@ -1565,7 +1638,15 @@ function Test-TargetResource
15651638
[Parameter()]
15661639
[ValidateSet('Group', 'Interactive', 'InteractiveOrPassword', 'None', 'Password', 'S4U', 'ServiceAccount')]
15671640
[System.String]
1568-
$LogonType
1641+
$LogonType,
1642+
1643+
[Parameter()]
1644+
[System.String]
1645+
$EventSubscription,
1646+
1647+
[Parameter()]
1648+
[System.String]
1649+
$Delay = '00:00:00'
15691650
)
15701651

15711652
$TaskPath = ConvertTo-NormalizedTaskPath -TaskPath $TaskPath
@@ -1580,7 +1661,16 @@ function Test-TargetResource
15801661

15811662
if ($PSBoundParameters.ContainsKey('RandomDelay'))
15821663
{
1583-
$PSBoundParameters['RandomDelay'] = (ConvertTo-TimeSpanFromTimeSpanString -TimeSpanString $RandomDelay).ToString()
1664+
if ($ScheduleType -eq 'OnEvent')
1665+
{
1666+
# A random delay is not supported when the ScheduleType is set to OnEvent.
1667+
Write-Verbose -Message ($script:localizedData.IgnoreRandomDelayWithTriggerTypeOnEvent -f $TaskName)
1668+
$null = $PSBoundParameters.Remove('RandomDelay')
1669+
}
1670+
else
1671+
{
1672+
$PSBoundParameters['RandomDelay'] = (ConvertTo-TimeSpanFromTimeSpanString -TimeSpanString $RandomDelay).ToString()
1673+
}
15841674
}
15851675

15861676
if ($PSBoundParameters.ContainsKey('RepetitionDuration'))

Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/MSFT_ScheduledTask.schema.mof

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ class MSFT_ScheduledTask : OMI_BaseResource
77
[Write, Description("The path to the .exe for this task")] string ActionExecutable;
88
[Write, Description("The arguments to pass the executable")] string ActionArguments;
99
[Write, Description("The working path to specify for the executable")] string ActionWorkingPath;
10-
[Write, Description("When should the task be executed"), ValueMap{"Once", "Daily", "Weekly", "AtStartup", "AtLogOn"}, Values{"Once", "Daily", "Weekly", "AtStartup", "AtLogOn"}] string ScheduleType;
10+
[Write, Description("When should the task be executed"), ValueMap{"Once", "Daily", "Weekly", "AtStartup", "AtLogOn", "OnEvent"}, Values{"Once", "Daily", "Weekly", "AtStartup", "AtLogOn", "OnEvent"}] string ScheduleType;
1111
[Write, Description("How many units (minutes, hours, days) between each run of this task?")] String RepeatInterval;
1212
[Write, Description("The time of day this task should start at - defaults to 12:00 AM. Not valid for AtLogon and AtStartup tasks")] DateTime StartTime;
1313
[Write, Description("Present if the task should exist, Absent if it should be removed"), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] string Ensure;
@@ -42,4 +42,6 @@ class MSFT_ScheduledTask : OMI_BaseResource
4242
[Write, Description("Indicates that Task Scheduler runs the task only when a network is available. Task Scheduler uses the NetworkID parameter and NetworkName parameter that you specify in this cmdlet to determine if the network is available.")] Boolean RunOnlyIfNetworkAvailable;
4343
[Write, Description("Specifies the level of user rights that Task Scheduler uses to run the tasks that are associated with the principal. Defaults to 'Limited'."), ValueMap{"Limited","Highest"}, Values{"Limited","Highest"}] String RunLevel;
4444
[Write, Description("Specifies the security logon method that Task Scheduler uses to run the tasks that are associated with the principal."), ValueMap{"Group","Interactive","InteractiveOrPassword","None","Password","S4U","ServiceAccount"}, Values{"Group","Interactive","InteractiveOrPassword","None","Password","S4U","ServiceAccount"}] String LogonType;
45+
[Write, Description("Specifies the EventSubscription in XML. This can be easily generated using the Windows Eventlog Viewer. For the query schema please check: https://docs.microsoft.com/en-us/windows/desktop/WES/queryschema-schema. Can only be used in combination with ScheduleType OnEvent")] String EventSubscription;
46+
[Write, Description("Specifies a delay to the start of the trigger. The delay is a static delay before the task is executed. Can only be used in combination with ScheduleType OnEvent")] String Delay;
4547
};

Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/en-US/MSFT_ScheduledTask.strings.psd1

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ ConvertFrom-StringData @'
1010
DaysIntervalError = DaysInterval must be greater than zero (0) for Daily schedules. DaysInterval specified is '{0}'.
1111
WeeksIntervalError = WeeksInterval must be greater than zero (0) for Weekly schedules. WeeksInterval specified is '{0}'.
1212
WeekDayMissingError = At least one weekday must be selected for Weekly schedule.
13+
OnEventSubscriptionError = No (valid) XML Event Subscription was provided. This is required when the scheduletype is OnEvent.
1314
TriggerCreationError = Error creating new scheduled task trigger.
1415
ConfigureTriggerRepetitionMessage = Configuring trigger repetition.
1516
RepetitionIntervalError = Repetition interval is set to '{0}' but repetition duration is '{1}'.
@@ -20,6 +21,8 @@ ConvertFrom-StringData @'
2021
CreateScheduledTaskPrincipalMessage = Creating scheduled task principal for account '{0}' using logon type '{1}'.
2122
RemovePreviousScheduledTaskMessage = Removing previous scheduled task '{0}' from '{1}'.
2223
CreateNewScheduledTaskMessage = Creating new scheduled task '{0}' in '{1}'.
24+
ConfigureTaskEventTrigger = Setting up an event based trigger on task {0}.
25+
IgnoreRandomDelayWithTriggerTypeOnEvent = The parameter RandomDelay in task {0} is ignored. A random delay is not supported when the trigger type is set to OnEvent.
2326
SetRepetitionTriggerMessage = Setting repetition trigger settings on task '{0}' in '{1}'.
2427
RegisterScheduledTaskMessage = Registering the scheduled task '{0}' in '{1}'.
2528
RetrieveScheduledTaskMessage = Retrieving the scheduled task '{0}' from '{1}'.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<#
2+
.EXAMPLE
3+
This example creates a scheduled task called 'TriggerOnServiceFailures' in the folder
4+
root folder. The task is delayed by exactly 30 seconds each time. The task will run when
5+
an error event 7001 of source Service Control Manager is generated in the system log.
6+
When a service crashes, it waits for 30 seconds and then starts a new PowerShell instance,
7+
in which the file c:\temp\seeme.txt get's created with the value 'Worked!'
8+
#>
9+
Configuration Example
10+
{
11+
param
12+
(
13+
[Parameter()]
14+
[System.String[]]
15+
$NodeName = 'localhost'
16+
)
17+
18+
Import-DscResource -ModuleName ComputerManagementDsc
19+
20+
Node $NodeName
21+
{
22+
ScheduledTask ServiceEventManager
23+
{
24+
TaskName = 'TriggerOnServiceFailures'
25+
Ensure = 'Present'
26+
ScheduleType = 'OnEvent'
27+
ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe'
28+
ActionArguments = '-Command Set-Content -Path c:\temp\seeme.txt -Value ''Worked!'''
29+
EventSubscription = '<QueryList><Query Id="0" Path="System"><Select Path="System">*[System[Provider[@Name=''Service Control Manager''] and (Level=2) and (EventID=7001)]]</Select></Query></QueryList>'
30+
Delay = '00:00:30'
31+
}
32+
}
33+
}

Tests/Integration/MSFT_ScheduledTask.Config.ps1

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,25 @@ Configuration ScheduledTaskExecuteAsAdd
168168
}
169169
}
170170

171+
Configuration ScheduledTaskOnEventAdd
172+
{
173+
Import-DscResource -ModuleName ComputerManagementDsc
174+
node 'localhost'
175+
{
176+
ScheduledTask ScheduledTaskOnEventAdd
177+
{
178+
TaskName = 'Test task OnEvent'
179+
TaskPath = '\ComputerManagementDsc\'
180+
Ensure = 'Present'
181+
ScheduleType = 'OnEvent'
182+
ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe'
183+
ActionArguments = '-Command Set-Content -Path c:\temp\seeme.txt -Value ''Worked!'''
184+
EventSubscription = '<QueryList><Query Id="0" Path="System"><Select Path="System">*[System[Provider[@Name=''Service Control Manager''] and (Level=2) and (EventID=7001)]]</Select></Query></QueryList>'
185+
Delay = '00:00:30'
186+
}
187+
}
188+
}
189+
171190
Configuration ScheduledTaskOnceMod
172191
{
173192
Import-DscResource -ModuleName ComputerManagementDsc
@@ -294,6 +313,25 @@ Configuration ScheduledTaskExecuteAsMod
294313
}
295314
}
296315

316+
Configuration ScheduledTaskOnEventMod
317+
{
318+
Import-DscResource -ModuleName ComputerManagementDsc
319+
node 'localhost'
320+
{
321+
ScheduledTask ScheduledTaskOnEventMod
322+
{
323+
TaskName = 'Test task OnEvent'
324+
TaskPath = '\ComputerManagementDsc\'
325+
Ensure = 'Present'
326+
ScheduleType = 'OnEvent'
327+
ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe'
328+
ActionArguments = '-Command Set-Content -Path c:\temp\seeme.txt -Value ''Worked!'''
329+
EventSubscription = '<QueryList><Query Id="0" Path="System"><Select Path="System">*[System[Provider[@Name=''Service Control Manager''] and (Level=2) and (EventID=7002)]]</Select></Query></QueryList>'
330+
Delay = '00:00:45'
331+
}
332+
}
333+
}
334+
297335
Configuration ScheduledTaskOnceDel
298336
{
299337
Import-DscResource -ModuleName ComputerManagementDsc
@@ -425,6 +463,25 @@ Configuration ScheduledTaskExecuteAsDel
425463
}
426464
}
427465

466+
Configuration ScheduledTaskOnEventDel
467+
{
468+
Import-DscResource -ModuleName ComputerManagementDsc
469+
node 'localhost'
470+
{
471+
ScheduledTask ScheduledTaskOnEventDel
472+
{
473+
TaskName = 'Test task OnEvent'
474+
TaskPath = '\ComputerManagementDsc\'
475+
Ensure = 'Absent'
476+
ScheduleType = 'OnEvent'
477+
ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe'
478+
ActionArguments = '-Command Set-Content -Path c:\temp\seeme.txt -Value ''Worked!'''
479+
EventSubscription = '<QueryList><Query Id="0" Path="System"><Select Path="System">*[System[Provider[@Name=''Service Control Manager''] and (Level=2) and (EventID=7001)]]</Select></Query></QueryList>'
480+
Delay = '00:00:30'
481+
}
482+
}
483+
}
484+
428485
Configuration ScheduledTaskDisableBuiltIn
429486
{
430487
Import-DscResource -ModuleName ComputerManagementDsc

Tests/Integration/MSFT_ScheduledTask.Integration.Tests.ps1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ try
3636
AtLogon = 'ScheduledTaskLogon'
3737
AtStartup = 'ScheduledTaskStartup'
3838
ExecuteAs = 'ScheduledTaskExecuteAs'
39+
OnEvent = 'ScheduledTaskOnEvent'
3940
}
4041

4142
$configData = @{

0 commit comments

Comments
 (0)