From 08c1f32f63f6854fef93c20b3e5dff10ba8777d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20Both?= Date: Tue, 3 Jul 2018 23:21:01 +0200 Subject: [PATCH 1/5] Adding support for event based triggers by the OnEvent schedule type --- .../MSFT_ScheduledTask.psm1 | 80 +++++++- .../MSFT_ScheduledTask.schema.mof | 2 + .../en-US/MSFT_ScheduledTask.strings.psd1 | 2 + Tests/Unit/MSFT_ScheduledTask.Tests.ps1 | 188 +++++++++++++++++- 4 files changed, 260 insertions(+), 12 deletions(-) diff --git a/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/MSFT_ScheduledTask.psm1 b/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/MSFT_ScheduledTask.psm1 index 7d7329d9..3623278f 100644 --- a/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/MSFT_ScheduledTask.psm1 +++ b/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/MSFT_ScheduledTask.psm1 @@ -234,7 +234,7 @@ function Get-TargetResource [Parameter()] [System.String] - [ValidateSet('Once', 'Daily', 'Weekly', 'AtStartup', 'AtLogOn')] + [ValidateSet('Once', 'Daily', 'Weekly', 'AtStartup', 'AtLogOn','OnEvent')] $ScheduleType, [Parameter()] @@ -376,7 +376,15 @@ function Get-TargetResource [Parameter()] [ValidateSet('Group', 'Interactive', 'InteractiveOrPassword', 'None', 'Password', 'S4U', 'ServiceAccount')] [System.String] - $LogonType + $LogonType, + + [Parameter()] + [System.String] + $EventSubscription, + + [Parameter()] + [System.String] + $Delay = '00:00:00' ) $TaskPath = ConvertTo-NormalizedTaskPath -TaskPath $TaskPath @@ -436,6 +444,12 @@ function Get-TargetResource break } + 'MSFT_TaskEventTrigger' + { + $returnScheduleType = 'OnEvent' + break + } + default { $returnScheduleType = '' @@ -510,6 +524,8 @@ function Get-TargetResource RunOnlyIfNetworkAvailable = $settings.RunOnlyIfNetworkAvailable RunLevel = [System.String] $task.Principal.RunLevel LogonType = [System.String] $task.Principal.LogonType + EventSubscription = $trigger.Subscription + Delay = ConvertTo-TimeSpanStringFromScheduledTaskString -TimeSpan $trigger.Delay } } } @@ -697,7 +713,7 @@ function Set-TargetResource [Parameter()] [System.String] - [ValidateSet('Once', 'Daily', 'Weekly', 'AtStartup', 'AtLogOn')] + [ValidateSet('Once', 'Daily', 'Weekly', 'AtStartup', 'AtLogOn','OnEvent')] $ScheduleType, [Parameter()] @@ -839,7 +855,15 @@ function Set-TargetResource [Parameter()] [ValidateSet('Group', 'Interactive', 'InteractiveOrPassword', 'None', 'Password', 'S4U', 'ServiceAccount')] [System.String] - $LogonType + $LogonType, + + [Parameter()] + [System.String] + $EventSubscription, + + [Parameter()] + [System.String] + $Delay = '00:00:00' ) $TaskPath = ConvertTo-NormalizedTaskPath -TaskPath $TaskPath @@ -902,6 +926,13 @@ function Set-TargetResource -ArgumentName DaysOfWeek } + if ($ScheduleType -eq 'OnEvent' -and -not([xml]$EventSubscription)) + { + New-InvalidArgumentException ` + -Message ($script:localizedData.OnEventSubscriptionError) ` + -ArgumentName EventSubscription + } + # Configure the action $actionParameters = @{ Execute = $ActionExecutable @@ -989,7 +1020,8 @@ function Set-TargetResource # Configure the trigger $triggerParameters = @{} - if ($RandomDelay -gt [System.TimeSpan]::FromSeconds(0)) + # A random delay is not supported when the scheduleType is set to OnEvent + if ($RandomDelay -gt [System.TimeSpan]::FromSeconds(0) -and $ScheduleType -ne 'OnEvent') { $triggerParameters.Add('RandomDelay', $RandomDelay) } @@ -1049,9 +1081,23 @@ function Set-TargetResource break } + + 'OnEvent' + { + Write-Verbose -Message ($script:localizedData.ConfigureTaskEventTrigger -f $TaskName) + + $cimTriggerClass = Get-CimClass -ClassName MSFT_TaskEventTrigger -Namespace Root/Microsoft/Windows/TaskScheduler:MSFT_TaskEventTrigger + $trigger = New-CimInstance -CimClass $cimTriggerClass -ClientOnly + $trigger.Enabled = $true + $trigger.Delay = (New-ScheduledTaskTrigger -RandomDelay $Delay -Once -At (Get-Date)).RandomDelay + $trigger.Subscription = $EventSubscription + } } - $trigger = New-ScheduledTaskTrigger @triggerParameters -ErrorAction SilentlyContinue + if($ScheduleType -ne 'OnEvent') + { + $trigger = New-ScheduledTaskTrigger @triggerParameters -ErrorAction SilentlyContinue + } if (-not $trigger) { @@ -1423,7 +1469,7 @@ function Test-TargetResource [Parameter()] [System.String] - [ValidateSet('Once', 'Daily', 'Weekly', 'AtStartup', 'AtLogOn')] + [ValidateSet('Once', 'Daily', 'Weekly', 'AtStartup', 'AtLogOn','OnEvent')] $ScheduleType, [Parameter()] @@ -1565,7 +1611,15 @@ function Test-TargetResource [Parameter()] [ValidateSet('Group', 'Interactive', 'InteractiveOrPassword', 'None', 'Password', 'S4U', 'ServiceAccount')] [System.String] - $LogonType + $LogonType, + + [Parameter()] + [System.String] + $EventSubscription, + + [Parameter()] + [System.String] + $Delay = '00:00:00' ) $TaskPath = ConvertTo-NormalizedTaskPath -TaskPath $TaskPath @@ -1580,7 +1634,15 @@ function Test-TargetResource if ($PSBoundParameters.ContainsKey('RandomDelay')) { - $PSBoundParameters['RandomDelay'] = (ConvertTo-TimeSpanFromTimeSpanString -TimeSpanString $RandomDelay).ToString() + if($ScheduleType -eq 'OnEvent') + { + # A random delay is not supported when the ScheduleType is set to OnEvent. + $null = $PSBoundParameters.Remove('RandomDelay') + } + else + { + $PSBoundParameters['RandomDelay'] = (ConvertTo-TimeSpanFromTimeSpanString -TimeSpanString $RandomDelay).ToString() + } } if ($PSBoundParameters.ContainsKey('RepetitionDuration')) diff --git a/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/MSFT_ScheduledTask.schema.mof b/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/MSFT_ScheduledTask.schema.mof index 494409fb..9280c25e 100644 --- a/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/MSFT_ScheduledTask.schema.mof +++ b/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/MSFT_ScheduledTask.schema.mof @@ -42,4 +42,6 @@ class MSFT_ScheduledTask : OMI_BaseResource [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; [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; [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; + [Write, Description("Specifies the EventSubscription in XML. This can be easily generated using the Windows Eventlog Viewer. Can only be used in combination with ScheduleType OnEvent")] String EventSubscription; + [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; }; diff --git a/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/en-US/MSFT_ScheduledTask.strings.psd1 b/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/en-US/MSFT_ScheduledTask.strings.psd1 index 31a11ec6..4598f3f6 100644 --- a/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/en-US/MSFT_ScheduledTask.strings.psd1 +++ b/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/en-US/MSFT_ScheduledTask.strings.psd1 @@ -10,6 +10,7 @@ ConvertFrom-StringData @' DaysIntervalError = DaysInterval must be greater than zero (0) for Daily schedules. DaysInterval specified is '{0}'. WeeksIntervalError = WeeksInterval must be greater than zero (0) for Weekly schedules. WeeksInterval specified is '{0}'. WeekDayMissingError = At least one weekday must be selected for Weekly schedule. + OnEventSubscriptionError = No (valid) XML Event Subscription was provided. This is required when the scheduletype is OnEvent. TriggerCreationError = Error creating new scheduled task trigger. ConfigureTriggerRepetitionMessage = Configuring trigger repetition. RepetitionIntervalError = Repetition interval is set to '{0}' but repetition duration is '{1}'. @@ -20,6 +21,7 @@ ConvertFrom-StringData @' CreateScheduledTaskPrincipalMessage = Creating scheduled task principal for account '{0}' using logon type '{1}'. RemovePreviousScheduledTaskMessage = Removing previous scheduled task '{0}' from '{1}'. CreateNewScheduledTaskMessage = Creating new scheduled task '{0}' in '{1}'. + ConfigureTaskEventTrigger = Setting up an event based trigger on task {0} SetRepetitionTriggerMessage = Setting repetition trigger settings on task '{0}' in '{1}'. RegisterScheduledTaskMessage = Registering the scheduled task '{0}' in '{1}'. RetrieveScheduledTaskMessage = Retrieving the scheduled task '{0}' from '{1}'. diff --git a/Tests/Unit/MSFT_ScheduledTask.Tests.ps1 b/Tests/Unit/MSFT_ScheduledTask.Tests.ps1 index ffae5045..08463258 100644 --- a/Tests/Unit/MSFT_ScheduledTask.Tests.ps1 +++ b/Tests/Unit/MSFT_ScheduledTask.Tests.ps1 @@ -1408,7 +1408,7 @@ try ScheduleType = 'Once' RepeatInterval = (New-TimeSpan -Minutes 20).ToString() RepetitionDuration = (New-TimeSpan -Hours 9).ToString() - Verbose = $True + Verbose = $False } Mock -CommandName Get-ScheduledTask -MockWith { @@ -1522,13 +1522,14 @@ try Interval = "PT15M" } CimClass = @{ - CimClassName = 'MSFT_TaskEventTrigger' + CimClassName = 'MSFT_TaskSessionStateChangeTrigger' } } Settings = [pscustomobject] @{ Enabled = $true } - } } + } + } It 'Should return the correct values from Get-TargetResource' { $result = Get-TargetResource @testParameters @@ -1546,6 +1547,187 @@ try Assert-MockCalled Register-ScheduledTask -Exactly -Times 1 } } + + Context 'When a scheduled task with an OnEvent scheduletype is in desired state' { + $testParameters = @{ + TaskName = 'Test task' + TaskPath = '\Test\' + ScheduleType = 'OnEvent' + ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' + EventSubscription = '' + Delay = '00:01:00' + Enable = $True + Verbose = $True + } + + Mock -CommandName Get-ScheduledTask -MockWith { + @{ + TaskName = $testParameters.TaskName + TaskPath = $testParameters.TaskPath + Actions = [pscustomobject] @{ + Execute = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' + } + Triggers = [pscustomobject] @{ + Delay = 'PT1M' + Subscription = $testParameters.EventSubscription + CimClass = @{ + CimClassName = 'MSFT_TaskEventTrigger' + } + } + Settings = [pscustomobject] @{ + Enabled = $true + } + } + } + + It 'Should return the correct values from Get-TargetResource' { + $result = Get-TargetResource @testParameters + $result.Enable | Should -Be $true + $result.Ensure | Should -Be 'Present' + $result.ScheduleType | Should -Be 'OnEvent' + $result.EventSubscription | Should -Be $testParameters.EventSubscription + $result.Delay | Should -Be $testParameters.Delay + } + + It 'Should return true from the test method' { + Test-TargetResource @testParameters | Should -Be $true + } + } + + Context 'When a scheduled task with an OnEvent scheduletype is needs to be created' { + $testParameters = @{ + TaskName = 'Test task' + TaskPath = '\Test\' + ScheduleType = 'OnEvent' + ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' + EventSubscription = '' + Delay = '00:01:00' + Enable = $True + Verbose = $True + } + + Mock -CommandName Get-ScheduledTask + + It 'Should return the correct values from Get-TargetResource' { + $result = Get-TargetResource @testParameters + $result.Ensure | Should -Be 'Absent' + } + + It 'Should return false from the test method' { + Test-TargetResource @testParameters | Should -Be $false + } + + It 'Should register the new scheduled task' { + Set-TargetResource @testParameters + Assert-MockCalled Register-ScheduledTask -Exactly -Times 1 -Scope It + } + } + + Context 'When a scheduled task with an OnEvent scheduletype needs to be updated' { + $testParameters = @{ + TaskName = 'Test task' + TaskPath = '\Test\' + ScheduleType = 'OnEvent' + ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' + EventSubscription = '' + Delay = '00:05:00' + Enable = $True + Verbose = $True + } + + Mock -CommandName Get-ScheduledTask -MockWith { + @{ + TaskName = $testParameters.TaskName + TaskPath = $testParameters.TaskPath + Actions = [pscustomobject] @{ + Execute = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' + } + Triggers = [pscustomobject] @{ + Delay = 'PT1M' + Subscription = '' + CimClass = @{ + CimClassName = 'MSFT_TaskEventTrigger' + } + } + Settings = [pscustomobject] @{ + Enabled = $true + } + } + } + + It 'Should return the correct values from Get-TargetResource' { + $result = Get-TargetResource @testParameters + $result.Enable | Should -Be $true + $result.Ensure | Should -Be 'Present' + $result.ScheduleType | Should -Be 'OnEvent' + } + + It 'Should return false from the test method' { + Test-TargetResource @testParameters | Should -Be $false + } + + It 'Should not call Register-ScheduledTask on an already registered task' { + Set-TargetResource @testParameters + Assert-MockCalled Register-ScheduledTask -Times 0 -Scope It + } + + It 'Should call Set-ScheduledTask to update the scheduled task with the new values' { + Set-TargetResource @testParameters + Assert-MockCalled Set-ScheduledTask -Times 1 -Scope It + } + } + + Context 'When a scheduled task with an OnEvent scheduletype is used on combination with unsupported parameters for this scheduletype' { + $testParameters = @{ + TaskName = 'Test task' + TaskPath = '\Test\' + ScheduleType = 'OnEvent' + ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' + EventSubscription = '' + RandomDelay = '01:00:00' + Delay = '00:01:00' + Enable = $True + Verbose = $True + } + + Mock -CommandName Get-ScheduledTask -MockWith { + @{ + TaskName = $testParameters.TaskName + TaskPath = $testParameters.TaskPath + Actions = [pscustomobject] @{ + Execute = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' + } + Triggers = [pscustomobject] @{ + Delay = 'PT1M' + Subscription = $testParameters.EventSubscription + CimClass = @{ + CimClassName = 'MSFT_TaskEventTrigger' + } + } + Settings = [pscustomobject] @{ + Enabled = $true + } + } + } + + It 'Should return the correct values from Get-TargetResource' { + $result = Get-TargetResource @testParameters + $result.Enable | Should -Be $true + $result.Ensure | Should -Be 'Present' + $result.ScheduleType | Should -Be 'OnEvent' + $result.RandomDelay | Should -Be '00:00:00' + } + + It 'Should return true from the test method - ignoring the RandomDelay parameter' { + Test-TargetResource @testParameters | Should -Be $true + } + + $testParameters.EventSubscription = 'InvalidXML' + + It 'When an EventSubscription cannot be parsed as valid XML an error is generated when changing the task' { + { Set-TargetResource @testParameters } | Should throw + } + } } } #endregion From b27136ccfaed3203607ac8431d2a64170c522fb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20Both?= Date: Tue, 3 Jul 2018 23:56:44 +0200 Subject: [PATCH 2/5] Adding example for OnEvent scheduled task configuration and adding help to parameters --- .../MSFT_ScheduledTask.psm1 | 24 ++++++++++++++ .../MSFT_ScheduledTask.schema.mof | 2 +- .../13-CreateScheduledTasksOnEvent.ps1 | 33 +++++++++++++++++++ 3 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 Modules/ComputerManagementDsc/Examples/Resources/ScheduledTask/13-CreateScheduledTasksOnEvent.ps1 diff --git a/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/MSFT_ScheduledTask.psm1 b/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/MSFT_ScheduledTask.psm1 index 3623278f..fadb7b55 100644 --- a/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/MSFT_ScheduledTask.psm1 +++ b/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/MSFT_ScheduledTask.psm1 @@ -201,6 +201,14 @@ $script:localizedData = Get-LocalizedData ` .PARAMETER LogonType Specifies the security logon method that Task Scheduler uses to run the tasks that are associated with the principal. Not used in Get-TargetResource. + + .PARAMETER EventSubscription + The event subscription in a string that can be parsed as valid XML. This parameter is only + valid in combination with the OnEvent Schedule Type. + + .PARAMETER Delay + The time to wait after an event based trigger was triggered. This parameter is only + valid in combination with the OnEvent Schedule Type. #> function Get-TargetResource { @@ -681,6 +689,14 @@ function Get-TargetResource .PARAMETER LogonType Specifies the security logon method that Task Scheduler uses to run the tasks that are associated with the principal. + + .PARAMETER EventSubscription + The event subscription in a string that can be parsed as valid XML. This parameter is only + valid in combination with the OnEvent Schedule Type. + + .PARAMETER Delay + The time to wait after an event based trigger was triggered. This parameter is only + valid in combination with the OnEvent Schedule Type. #> function Set-TargetResource { @@ -1436,6 +1452,14 @@ function Set-TargetResource .PARAMETER LogonType Specifies the security logon method that Task Scheduler uses to run the tasks that are associated with the principal. + + .PARAMETER EventSubscription + The event subscription in a string that can be parsed as valid XML. This parameter is only + valid in combination with the OnEvent Schedule Type. + + .PARAMETER Delay + The time to wait after an event based trigger was triggered. This parameter is only + valid in combination with the OnEvent Schedule Type. #> function Test-TargetResource { diff --git a/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/MSFT_ScheduledTask.schema.mof b/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/MSFT_ScheduledTask.schema.mof index 9280c25e..6e33384b 100644 --- a/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/MSFT_ScheduledTask.schema.mof +++ b/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/MSFT_ScheduledTask.schema.mof @@ -7,7 +7,7 @@ class MSFT_ScheduledTask : OMI_BaseResource [Write, Description("The path to the .exe for this task")] string ActionExecutable; [Write, Description("The arguments to pass the executable")] string ActionArguments; [Write, Description("The working path to specify for the executable")] string ActionWorkingPath; - [Write, Description("When should the task be executed"), ValueMap{"Once", "Daily", "Weekly", "AtStartup", "AtLogOn"}, Values{"Once", "Daily", "Weekly", "AtStartup", "AtLogOn"}] string ScheduleType; + [Write, Description("When should the task be executed"), ValueMap{"Once", "Daily", "Weekly", "AtStartup", "AtLogOn", "OnEvent"}, Values{"Once", "Daily", "Weekly", "AtStartup", "AtLogOn", "OnEvent"}] string ScheduleType; [Write, Description("How many units (minutes, hours, days) between each run of this task?")] String RepeatInterval; [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; [Write, Description("Present if the task should exist, Absent if it should be removed"), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] string Ensure; diff --git a/Modules/ComputerManagementDsc/Examples/Resources/ScheduledTask/13-CreateScheduledTasksOnEvent.ps1 b/Modules/ComputerManagementDsc/Examples/Resources/ScheduledTask/13-CreateScheduledTasksOnEvent.ps1 new file mode 100644 index 00000000..f1cffcfb --- /dev/null +++ b/Modules/ComputerManagementDsc/Examples/Resources/ScheduledTask/13-CreateScheduledTasksOnEvent.ps1 @@ -0,0 +1,33 @@ +<# + .EXAMPLE + This example creates a scheduled task called 'TriggerOnServiceFailures' in the folder + root folder. The task is delayed by exactly 30 seconds each time. The task will run when + an error event 7001 of source Service Control Manager is generated in the system log. + When a service crashes, it waits for 30 seconds and then starts a new PowerShell instance, + in which the command Invoke-ServiceCrashReport will be executed. +#> +Configuration Example +{ + param + ( + [Parameter()] + [System.String[]] + $NodeName = 'localhost' + ) + + Import-DscResource -ModuleName ComputerManagementDsc + + Node $NodeName + { + ScheduledTask ServiceEventManager + { + TaskName = 'TriggerOnServiceFailures' + Ensure = 'Present' + ScheduleType = 'OnEvent' + ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' + ActionArguments = '-Command Invoke-ServiceCrashReport' + EventSubscription = '' + Delay = '00:00:30' + } + } +} From d2f0f26c30b158af1e05789cd5de8f44a04e83cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20Both?= Date: Wed, 4 Jul 2018 00:12:22 +0200 Subject: [PATCH 3/5] Update changelog --- CHANGELOG.md | 2 ++ .../ScheduledTask/13-CreateScheduledTasksOnEvent.ps1 | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c882fe49..fecf04fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ - Moved strings to localization file. - Changed the scope from Global to Script in MSFT_ScheduledTask.Integration.Tests.ps1 - Changed the scope from Global to Script ComputerManagementDsc.Common.Tests.ps1 +- ScheduledTask: + - Added support for event based triggers, implemented using the ScheduleType OnEvent ## 5.1.0.0 diff --git a/Modules/ComputerManagementDsc/Examples/Resources/ScheduledTask/13-CreateScheduledTasksOnEvent.ps1 b/Modules/ComputerManagementDsc/Examples/Resources/ScheduledTask/13-CreateScheduledTasksOnEvent.ps1 index f1cffcfb..c34b22b6 100644 --- a/Modules/ComputerManagementDsc/Examples/Resources/ScheduledTask/13-CreateScheduledTasksOnEvent.ps1 +++ b/Modules/ComputerManagementDsc/Examples/Resources/ScheduledTask/13-CreateScheduledTasksOnEvent.ps1 @@ -4,7 +4,7 @@ root folder. The task is delayed by exactly 30 seconds each time. The task will run when an error event 7001 of source Service Control Manager is generated in the system log. When a service crashes, it waits for 30 seconds and then starts a new PowerShell instance, - in which the command Invoke-ServiceCrashReport will be executed. + in which the file c:\temp\seeme.txt get's created with the value 'Worked!' #> Configuration Example { @@ -25,7 +25,7 @@ Configuration Example Ensure = 'Present' ScheduleType = 'OnEvent' ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' - ActionArguments = '-Command Invoke-ServiceCrashReport' + ActionArguments = '-Command Set-Content -Path c:\temp\seeme.txt -Value ''Worked!''' EventSubscription = '' Delay = '00:00:30' } From 81c3e833ee73da709ab5bb2d5a5bb2efa1397b8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20Both?= Date: Wed, 4 Jul 2018 00:28:14 +0200 Subject: [PATCH 4/5] Update ValidateSet formatting for ScheduleType parameter --- .../DSCResources/MSFT_ScheduledTask/MSFT_ScheduledTask.psm1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/MSFT_ScheduledTask.psm1 b/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/MSFT_ScheduledTask.psm1 index fadb7b55..d01b2289 100644 --- a/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/MSFT_ScheduledTask.psm1 +++ b/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/MSFT_ScheduledTask.psm1 @@ -242,7 +242,7 @@ function Get-TargetResource [Parameter()] [System.String] - [ValidateSet('Once', 'Daily', 'Weekly', 'AtStartup', 'AtLogOn','OnEvent')] + [ValidateSet('Once', 'Daily', 'Weekly', 'AtStartup', 'AtLogOn', 'OnEvent')] $ScheduleType, [Parameter()] @@ -729,7 +729,7 @@ function Set-TargetResource [Parameter()] [System.String] - [ValidateSet('Once', 'Daily', 'Weekly', 'AtStartup', 'AtLogOn','OnEvent')] + [ValidateSet('Once', 'Daily', 'Weekly', 'AtStartup', 'AtLogOn', 'OnEvent')] $ScheduleType, [Parameter()] @@ -1493,7 +1493,7 @@ function Test-TargetResource [Parameter()] [System.String] - [ValidateSet('Once', 'Daily', 'Weekly', 'AtStartup', 'AtLogOn','OnEvent')] + [ValidateSet('Once', 'Daily', 'Weekly', 'AtStartup', 'AtLogOn', 'OnEvent')] $ScheduleType, [Parameter()] From ad0186427b0ec7ada7b6ecc7aa3a5e2c5c1e26bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20Both?= Date: Sun, 22 Jul 2018 00:23:15 +0200 Subject: [PATCH 5/5] Fixing code based on review adding integration tests and changing the way to get a DateInterval string to use System.Xml.XmlConvert --- CHANGELOG.md | 1 + .../MSFT_ScheduledTask.psm1 | 22 +++--- .../MSFT_ScheduledTask.schema.mof | 2 +- .../en-US/MSFT_ScheduledTask.strings.psd1 | 3 +- .../Integration/MSFT_ScheduledTask.Config.ps1 | 57 ++++++++++++++ .../MSFT_ScheduledTask.Integration.Tests.ps1 | 1 + Tests/Unit/MSFT_ScheduledTask.Tests.ps1 | 74 +++++++++---------- 7 files changed, 112 insertions(+), 48 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fecf04fb..197b3942 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ - Changed the scope from Global to Script ComputerManagementDsc.Common.Tests.ps1 - ScheduledTask: - Added support for event based triggers, implemented using the ScheduleType OnEvent + fixes [Issue #167](https://github.com/PowerShell/ComputerManagementDsc/issues/167) ## 5.1.0.0 diff --git a/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/MSFT_ScheduledTask.psm1 b/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/MSFT_ScheduledTask.psm1 index d01b2289..4210a65e 100644 --- a/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/MSFT_ScheduledTask.psm1 +++ b/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/MSFT_ScheduledTask.psm1 @@ -204,7 +204,8 @@ $script:localizedData = Get-LocalizedData ` .PARAMETER EventSubscription The event subscription in a string that can be parsed as valid XML. This parameter is only - valid in combination with the OnEvent Schedule Type. + valid in combination with the OnEvent Schedule Type. For the query schema please check: + https://docs.microsoft.com/en-us/windows/desktop/WES/queryschema-schema .PARAMETER Delay The time to wait after an event based trigger was triggered. This parameter is only @@ -692,7 +693,8 @@ function Get-TargetResource .PARAMETER EventSubscription The event subscription in a string that can be parsed as valid XML. This parameter is only - valid in combination with the OnEvent Schedule Type. + valid in combination with the OnEvent Schedule Type. For the query schema please check: + https://docs.microsoft.com/en-us/windows/desktop/WES/queryschema-schema .PARAMETER Delay The time to wait after an event based trigger was triggered. This parameter is only @@ -942,7 +944,7 @@ function Set-TargetResource -ArgumentName DaysOfWeek } - if ($ScheduleType -eq 'OnEvent' -and -not([xml]$EventSubscription)) + if ($ScheduleType -eq 'OnEvent' -and -not ([xml]$EventSubscription)) { New-InvalidArgumentException ` -Message ($script:localizedData.OnEventSubscriptionError) ` @@ -1098,19 +1100,19 @@ function Set-TargetResource break } - 'OnEvent' + 'OnEvent' { - Write-Verbose -Message ($script:localizedData.ConfigureTaskEventTrigger -f $TaskName) + Write-Verbose -Message ($script:localizedData.ConfigureTaskEventTrigger -f $TaskName) $cimTriggerClass = Get-CimClass -ClassName MSFT_TaskEventTrigger -Namespace Root/Microsoft/Windows/TaskScheduler:MSFT_TaskEventTrigger $trigger = New-CimInstance -CimClass $cimTriggerClass -ClientOnly $trigger.Enabled = $true - $trigger.Delay = (New-ScheduledTaskTrigger -RandomDelay $Delay -Once -At (Get-Date)).RandomDelay + $trigger.Delay = [System.Xml.XmlConvert]::ToString([timespan]$Delay) $trigger.Subscription = $EventSubscription } } - if($ScheduleType -ne 'OnEvent') + if ($ScheduleType -ne 'OnEvent') { $trigger = New-ScheduledTaskTrigger @triggerParameters -ErrorAction SilentlyContinue } @@ -1455,7 +1457,8 @@ function Set-TargetResource .PARAMETER EventSubscription The event subscription in a string that can be parsed as valid XML. This parameter is only - valid in combination with the OnEvent Schedule Type. + valid in combination with the OnEvent Schedule Type. For the query schema please check: + https://docs.microsoft.com/en-us/windows/desktop/WES/queryschema-schema .PARAMETER Delay The time to wait after an event based trigger was triggered. This parameter is only @@ -1658,9 +1661,10 @@ function Test-TargetResource if ($PSBoundParameters.ContainsKey('RandomDelay')) { - if($ScheduleType -eq 'OnEvent') + if ($ScheduleType -eq 'OnEvent') { # A random delay is not supported when the ScheduleType is set to OnEvent. + Write-Verbose -Message ($script:localizedData.IgnoreRandomDelayWithTriggerTypeOnEvent -f $TaskName) $null = $PSBoundParameters.Remove('RandomDelay') } else diff --git a/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/MSFT_ScheduledTask.schema.mof b/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/MSFT_ScheduledTask.schema.mof index 6e33384b..4d40f88a 100644 --- a/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/MSFT_ScheduledTask.schema.mof +++ b/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/MSFT_ScheduledTask.schema.mof @@ -42,6 +42,6 @@ class MSFT_ScheduledTask : OMI_BaseResource [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; [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; [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; - [Write, Description("Specifies the EventSubscription in XML. This can be easily generated using the Windows Eventlog Viewer. Can only be used in combination with ScheduleType OnEvent")] String EventSubscription; + [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; [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; }; diff --git a/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/en-US/MSFT_ScheduledTask.strings.psd1 b/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/en-US/MSFT_ScheduledTask.strings.psd1 index 4598f3f6..d811266f 100644 --- a/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/en-US/MSFT_ScheduledTask.strings.psd1 +++ b/Modules/ComputerManagementDsc/DSCResources/MSFT_ScheduledTask/en-US/MSFT_ScheduledTask.strings.psd1 @@ -21,7 +21,8 @@ ConvertFrom-StringData @' CreateScheduledTaskPrincipalMessage = Creating scheduled task principal for account '{0}' using logon type '{1}'. RemovePreviousScheduledTaskMessage = Removing previous scheduled task '{0}' from '{1}'. CreateNewScheduledTaskMessage = Creating new scheduled task '{0}' in '{1}'. - ConfigureTaskEventTrigger = Setting up an event based trigger on task {0} + ConfigureTaskEventTrigger = Setting up an event based trigger on task {0}. + IgnoreRandomDelayWithTriggerTypeOnEvent = The parameter RandomDelay in task {0} is ignored. A random delay is not supported when the trigger type is set to OnEvent. SetRepetitionTriggerMessage = Setting repetition trigger settings on task '{0}' in '{1}'. RegisterScheduledTaskMessage = Registering the scheduled task '{0}' in '{1}'. RetrieveScheduledTaskMessage = Retrieving the scheduled task '{0}' from '{1}'. diff --git a/Tests/Integration/MSFT_ScheduledTask.Config.ps1 b/Tests/Integration/MSFT_ScheduledTask.Config.ps1 index b3d85910..8195dff4 100644 --- a/Tests/Integration/MSFT_ScheduledTask.Config.ps1 +++ b/Tests/Integration/MSFT_ScheduledTask.Config.ps1 @@ -168,6 +168,25 @@ Configuration ScheduledTaskExecuteAsAdd } } +Configuration ScheduledTaskOnEventAdd +{ + Import-DscResource -ModuleName ComputerManagementDsc + node 'localhost' + { + ScheduledTask ScheduledTaskOnEventAdd + { + TaskName = 'Test task OnEvent' + TaskPath = '\ComputerManagementDsc\' + Ensure = 'Present' + ScheduleType = 'OnEvent' + ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' + ActionArguments = '-Command Set-Content -Path c:\temp\seeme.txt -Value ''Worked!''' + EventSubscription = '' + Delay = '00:00:30' + } + } +} + Configuration ScheduledTaskOnceMod { Import-DscResource -ModuleName ComputerManagementDsc @@ -294,6 +313,25 @@ Configuration ScheduledTaskExecuteAsMod } } +Configuration ScheduledTaskOnEventMod +{ + Import-DscResource -ModuleName ComputerManagementDsc + node 'localhost' + { + ScheduledTask ScheduledTaskOnEventMod + { + TaskName = 'Test task OnEvent' + TaskPath = '\ComputerManagementDsc\' + Ensure = 'Present' + ScheduleType = 'OnEvent' + ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' + ActionArguments = '-Command Set-Content -Path c:\temp\seeme.txt -Value ''Worked!''' + EventSubscription = '' + Delay = '00:00:45' + } + } +} + Configuration ScheduledTaskOnceDel { Import-DscResource -ModuleName ComputerManagementDsc @@ -425,6 +463,25 @@ Configuration ScheduledTaskExecuteAsDel } } +Configuration ScheduledTaskOnEventDel +{ + Import-DscResource -ModuleName ComputerManagementDsc + node 'localhost' + { + ScheduledTask ScheduledTaskOnEventDel + { + TaskName = 'Test task OnEvent' + TaskPath = '\ComputerManagementDsc\' + Ensure = 'Absent' + ScheduleType = 'OnEvent' + ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' + ActionArguments = '-Command Set-Content -Path c:\temp\seeme.txt -Value ''Worked!''' + EventSubscription = '' + Delay = '00:00:30' + } + } +} + Configuration ScheduledTaskDisableBuiltIn { Import-DscResource -ModuleName ComputerManagementDsc diff --git a/Tests/Integration/MSFT_ScheduledTask.Integration.Tests.ps1 b/Tests/Integration/MSFT_ScheduledTask.Integration.Tests.ps1 index 37575fc4..38ae8f2f 100644 --- a/Tests/Integration/MSFT_ScheduledTask.Integration.Tests.ps1 +++ b/Tests/Integration/MSFT_ScheduledTask.Integration.Tests.ps1 @@ -36,6 +36,7 @@ try AtLogon = 'ScheduledTaskLogon' AtStartup = 'ScheduledTaskStartup' ExecuteAs = 'ScheduledTaskExecuteAs' + OnEvent = 'ScheduledTaskOnEvent' } $configData = @{ diff --git a/Tests/Unit/MSFT_ScheduledTask.Tests.ps1 b/Tests/Unit/MSFT_ScheduledTask.Tests.ps1 index 08463258..e3943a7a 100644 --- a/Tests/Unit/MSFT_ScheduledTask.Tests.ps1 +++ b/Tests/Unit/MSFT_ScheduledTask.Tests.ps1 @@ -102,7 +102,7 @@ try ScheduleType = 'Once' RepeatInterval = (New-TimeSpan -Minutes 15).ToString() RepetitionDuration = (New-TimeSpan -Minutes 150).ToString() - Verbose = $True + Verbose = $true } Mock -CommandName Get-ScheduledTask -MockWith { return $null } @@ -130,7 +130,7 @@ try RepeatInterval = (New-TimeSpan -Minutes 15).ToString() RepetitionDuration = (New-TimeSpan -Minutes 15).ToString() Ensure = 'Absent' - Verbose = $True + Verbose = $true } Mock -CommandName Get-ScheduledTask -MockWith { @@ -174,7 +174,7 @@ try TaskName = 'Test task' TaskPath = '\Test\' Enable = $false - Verbose = $True + Verbose = $true } Mock -CommandName Get-ScheduledTask -MockWith { @@ -219,7 +219,7 @@ try TaskName = 'Test task' TaskPath = '\Test\' Ensure = 'Absent' - Verbose = $True + Verbose = $true } Mock -CommandName Get-ScheduledTask -MockWith { @@ -271,7 +271,7 @@ try ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' ScheduleType = 'Once' Ensure = 'Absent' - Verbose = $True + Verbose = $true } Mock -CommandName Get-ScheduledTask @@ -294,7 +294,7 @@ try ScheduleType = 'Once' RepeatInterval = (New-TimeSpan -Minutes 15).ToString() RepetitionDuration = (New-TimeSpan -Minutes 150).ToString() - Verbose = $True + Verbose = $true } Mock -CommandName Get-ScheduledTask -MockWith { @@ -346,7 +346,7 @@ try ScheduleType = 'Once' RepeatInterval = (New-TimeSpan -Minutes 15).ToString() RepetitionDuration = (New-TimeSpan -Minutes 30).ToString() - Verbose = $True + Verbose = $true } Mock -CommandName Get-ScheduledTask -MockWith { @@ -393,7 +393,7 @@ try ScheduleType = 'Once' RepeatInterval = (New-TimeSpan -Hours 4).ToString() RepetitionDuration = (New-TimeSpan -Hours 8).ToString() - Verbose = $True + Verbose = $true } Mock -CommandName Get-ScheduledTask -MockWith { @@ -445,7 +445,7 @@ try ScheduleType = 'Once' RepeatInterval = (New-TimeSpan -Hours 4).ToString() RepetitionDuration = (New-TimeSpan -Hours 8).ToString() - Verbose = $True + Verbose = $true } Mock -CommandName Get-ScheduledTask -MockWith { @@ -491,7 +491,7 @@ try ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' ScheduleType = 'Daily' DaysInterval = 3 - Verbose = $True + Verbose = $true } Mock -CommandName Get-ScheduledTask -MockWith { @@ -542,7 +542,7 @@ try ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' ScheduleType = 'Daily' DaysInterval = 3 - Verbose = $True + Verbose = $true } Mock -CommandName Get-ScheduledTask -MockWith { @@ -587,7 +587,7 @@ try RepeatInterval = (New-TimeSpan -Minutes 15).ToString() RepetitionDuration = (New-TimeSpan -Hours 8).ToString() ExecuteAsCredential = New-Object System.Management.Automation.PSCredential ('DEMO\RightUser', (ConvertTo-SecureString 'ExamplePassword' -AsPlainText -Force)) - Verbose = $True + Verbose = $true } Mock -CommandName Get-ScheduledTask -MockWith { @@ -641,7 +641,7 @@ try RepetitionDuration = (New-TimeSpan -Hours 8).ToString() ExecuteAsCredential = New-Object System.Management.Automation.PSCredential ('DEMO\RightUser', (ConvertTo-SecureString 'ExamplePassword' -AsPlainText -Force)) LogonType = 'S4U' - Verbose = $True + Verbose = $true } Mock -CommandName Get-ScheduledTask -MockWith { @@ -697,7 +697,7 @@ try RepetitionDuration = (New-TimeSpan -Hours 8).ToString() ExecuteAsCredential = New-Object System.Management.Automation.PSCredential ('DEMO\RightUser', (ConvertTo-SecureString 'ExamplePassword' -AsPlainText -Force)) RunLevel = 'Highest' - Verbose = $True + Verbose = $true } Mock -CommandName Get-ScheduledTask -MockWith { @@ -752,7 +752,7 @@ try ScheduleType = 'Once' RepeatInterval = (New-TimeSpan -Minutes 15).ToString() RepetitionDuration = (New-TimeSpan -Hours 8).ToString() - Verbose = $True + Verbose = $true } Mock -CommandName Get-ScheduledTask -MockWith { @@ -806,7 +806,7 @@ try ScheduleType = 'Once' RepeatInterval = (New-TimeSpan -Minutes 15).ToString() RepetitionDuration = (New-TimeSpan -Hours 8).ToString() - Verbose = $True + Verbose = $true } Mock -CommandName Get-ScheduledTask -MockWith { @@ -860,7 +860,7 @@ try RepeatInterval = (New-TimeSpan -Minutes 15).ToString() RepetitionDuration = (New-TimeSpan -Hours 8).ToString() Enable = $false - Verbose = $True + Verbose = $true } Mock -CommandName Get-ScheduledTask -MockWith { @@ -919,7 +919,7 @@ try RepetitionDuration = (New-TimeSpan -Hours 8).ToString() ExecutionTimeLimit = (New-TimeSpan -Seconds 0).ToString() Enable = $true - Verbose = $True + Verbose = $true } Mock -CommandName Get-ScheduledTask -MockWith { @@ -982,7 +982,7 @@ try ExecutionTimeLimit = (New-TimeSpan -Minutes 7).ToString() RestartInterval = (New-TimeSpan -Minutes 8).ToString() Enable = $true - Verbose = $True + Verbose = $true } Mock -CommandName Get-ScheduledTask -MockWith { @@ -1041,7 +1041,7 @@ try RepeatInterval = (New-TimeSpan -Minutes 15).ToString() RepetitionDuration = (New-TimeSpan -Hours 8).ToString() Enable = $false - Verbose = $True + Verbose = $true } Mock -CommandName Get-ScheduledTask -MockWith { @@ -1093,7 +1093,7 @@ try RepeatInterval = (New-TimeSpan -Minutes 15).ToString() RepetitionDuration = (New-TimeSpan -Hours 8).ToString() Enable = $true - Verbose = $True + Verbose = $true } Mock -CommandName Get-ScheduledTask -MockWith { @@ -1149,7 +1149,7 @@ try ScheduleType = 'Once' RepeatInterval = (New-TimeSpan -Minutes 15).ToString() RepetitionDuration = (New-TimeSpan -Hours 8).ToString() - Verbose = $True + Verbose = $true } Mock -CommandName Get-ScheduledTask -MockWith { @@ -1227,7 +1227,7 @@ try IdleDuration = (New-TimeSpan -Minutes 6).ToString() ExecutionTimeLimit = (New-TimeSpan -Minutes 7).ToString() RestartInterval = (New-TimeSpan -Minutes 8).ToString() - Verbose = $True + Verbose = $true } Mock -CommandName Get-ScheduledTask -MockWith { @@ -1293,7 +1293,7 @@ try IdleDuration = (New-TimeSpan -Minutes 6).ToString() ExecutionTimeLimit = (New-TimeSpan -Minutes 7).ToString() RestartInterval = (New-TimeSpan -Minutes 8).ToString() - Verbose = $True + Verbose = $true } Mock -CommandName Get-ScheduledTask -MockWith { @@ -1355,7 +1355,7 @@ try ScheduleType = 'Once' RepeatInterval = (New-TimeSpan -Minutes 20).ToString() RepetitionDuration = 'Indefinitely' - Verbose = $True + Verbose = $true } Mock -CommandName Get-ScheduledTask -MockWith { @@ -1408,7 +1408,7 @@ try ScheduleType = 'Once' RepeatInterval = (New-TimeSpan -Minutes 20).ToString() RepetitionDuration = (New-TimeSpan -Hours 9).ToString() - Verbose = $False + Verbose = $true } Mock -CommandName Get-ScheduledTask -MockWith { @@ -1461,7 +1461,7 @@ try ScheduleType = 'Once' RepeatInterval = (New-TimeSpan -Minutes 20).ToString() RepetitionDuration = 'Indefinitely' - Verbose = $True + Verbose = $true } Mock -CommandName Get-ScheduledTask -MockWith { @@ -1506,7 +1506,7 @@ try TaskName = 'Test task' TaskPath = '\Test\' Enable = $false - Verbose = $True + Verbose = $true } Mock -CommandName Get-ScheduledTask -MockWith { @@ -1556,8 +1556,8 @@ try ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' EventSubscription = '' Delay = '00:01:00' - Enable = $True - Verbose = $True + Enable = $true + Verbose = $true } Mock -CommandName Get-ScheduledTask -MockWith { @@ -1594,7 +1594,7 @@ try } } - Context 'When a scheduled task with an OnEvent scheduletype is needs to be created' { + Context 'When a scheduled task with an OnEvent scheduletype needs to be created' { $testParameters = @{ TaskName = 'Test task' TaskPath = '\Test\' @@ -1602,8 +1602,8 @@ try ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' EventSubscription = '' Delay = '00:01:00' - Enable = $True - Verbose = $True + Enable = $true + Verbose = $true } Mock -CommandName Get-ScheduledTask @@ -1631,8 +1631,8 @@ try ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' EventSubscription = '' Delay = '00:05:00' - Enable = $True - Verbose = $True + Enable = $true + Verbose = $true } Mock -CommandName Get-ScheduledTask -MockWith { @@ -1686,8 +1686,8 @@ try EventSubscription = '' RandomDelay = '01:00:00' Delay = '00:01:00' - Enable = $True - Verbose = $True + Enable = $true + Verbose = $true } Mock -CommandName Get-ScheduledTask -MockWith {