From 6f89a65dee8b156757c7d149863325c6a5f58b6e Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Tue, 26 Nov 2024 16:20:15 +0000 Subject: [PATCH 01/23] Sort StartTime handling --- CHANGELOG.md | 13 +++++ .../DSC_ScheduledTask/DSC_ScheduledTask.psm1 | 53 ++++++++++--------- .../DSC_ScheduledTask.schema.mof | 2 +- .../DSCResources/DSC_ScheduledTask/README.md | 8 +++ .../en-US/DSC_ScheduledTask.strings.psd1 | 1 - ...ynchronizeAcrossTimeZoneEnabled_Config.ps1 | 6 +-- 6 files changed, 54 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e1d0ce1..0ab8ffc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - BREAKING CHANGE: ScheduledTask + - Fixed SynchronizeAcrossTimeZone issue where Test always throws False when a date & time is used + where Daylight Savings Time is in operation. Fixes [Issue #374](https://github.com/dsccommunity/ComputerManagementDsc/issues/374). - Fixed User parameter to correctly return the user that triggers an AtLogon or OnSessionState Schedule Type, instead of the current value of ExecuteAsCredential. This parameter is only valid when using the AtLogon and OnSessionState Schedule Types. @@ -41,12 +43,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - BREAKING CHANGE: ScheduledTask + - StartTime is now processed on the device, rather than at compile time. This makes it possible + to configure start times based on each device's timezone, rather than being fixed to the time zone + configured on the device where the Desired State Configuration compilation was run. - Allow StartTime to be used to set the 'Activate' setting when adding ScheduleType triggers other than 'Once', 'Daily' and 'Weekly'. + - Changed the default StartTime date from today to 1st January 1980 to prevent configuration flip flopping, + and added note to configuration README to advise always supplying a date, and not just a time. + Fixes [Issue #148](https://github.com/dsccommunity/ComputerManagementDsc/issues/148). + Fixes [Issue #411](https://github.com/dsccommunity/ComputerManagementDsc/issues/411). + - Added examples & note to configuration README to supply a timezone when using SynchronizeAcrossTimeZone. + - Allow SynchronizeAcrossTimeZone to be used when adding ScheduleType triggers other than 'Once', + 'Daily' and 'Weekly'. - Updated Delay parameter to support ScheduleType AtLogon, AtStartup, AtCreation, OnSessionState. Fixes [Issue #345](https://github.com/dsccommunity/ComputerManagementDsc/issues/345). - Updated User parameter for use with ScheduleType OnSessionState in addition to AtLogon. - Updated integration tests to ensure resource and configuration names are matching. + - Updated Test-DateStringContainsTimeZone to process with UTC date strings using Zulu 'Z' string. - Converted tests to Pester 5 - Rename Delete-ADSIObject to Delete-ADSIObject to satisfy HQRM diff --git a/source/DSCResources/DSC_ScheduledTask/DSC_ScheduledTask.psm1 b/source/DSCResources/DSC_ScheduledTask/DSC_ScheduledTask.psm1 index 0125e405..73ebbbc3 100644 --- a/source/DSCResources/DSC_ScheduledTask/DSC_ScheduledTask.psm1 +++ b/source/DSCResources/DSC_ScheduledTask/DSC_ScheduledTask.psm1 @@ -97,7 +97,8 @@ function Get-TargetResource How many units (minutes, hours, days) between each run of this task? .PARAMETER StartTime - The time of day this task should start at, or activate on - defaults to 12:00 AM. + The date and time of day this task should start at, or activate on, represented + as a string for local conversion to DateTime format - defaults to 1st January 1980 at 12:00 AM. .PARAMETER SynchronizeAcrossTimeZone Enable the scheduled task option to synchronize across time zones. This is enabled @@ -301,8 +302,8 @@ function Set-TargetResource $RepeatInterval = '00:00:00', [Parameter()] - [System.DateTime] - $StartTime = [System.DateTime]::Today, + [System.String] + $StartTime = [System.DateTime]::Parse("1980-01-01T00:00:00").ToString('s'), [Parameter()] [System.Boolean] @@ -480,6 +481,9 @@ function Set-TargetResource Write-Verbose -Message ($script:localizedData.SetScheduledTaskMessage -f $TaskName, $TaskPath) + # Convert the strings containing dates & times to DateTime objects + [System.DateTime] $StartTime = [System.DateTime]::Parse($StartTime) + # Convert the strings containing time spans to TimeSpan Objects [System.TimeSpan] $RepeatInterval = ConvertTo-TimeSpanFromTimeSpanString -TimeSpanString $RepeatInterval [System.TimeSpan] $RandomDelay = ConvertTo-TimeSpanFromTimeSpanString -TimeSpanString $RandomDelay @@ -574,13 +578,6 @@ function Set-TargetResource -ArgumentName ExecuteAsGMSA } - if ($SynchronizeAcrossTimeZone -and ($ScheduleType -notin @('Once', 'Daily', 'Weekly'))) - { - New-InvalidArgumentException ` - -Message ($script:localizedData.SynchronizeAcrossTimeZoneInvalidScheduleType) ` - -ArgumentName SynchronizeAcrossTimeZone - } - # Configure the action $actionParameters = @{ Execute = $ActionExecutable @@ -1038,8 +1035,11 @@ function Set-TargetResource 2018-09-27T18:45:08 - The problem in New-ScheduledTaskTrigger is that it always writes the time the format that - includes the full timezone offset (W2016 behaviour, W2012R2 does it the other way around). + The problem in New-ScheduledTaskTrigger is that it always writes the time in the UTC format, which + includes the full timezone offset: (W2016+ behaviour, W2012R2 does it the other way around) + + 2018-09-27 16:45:08Z + Which means "Synchronize across time zones" is enabled by default on W2016 and disabled by default on W2012R2. To prevent that, we are overwriting the StartBoundary here to insert the time in the format we want it, so we can enable or disable "Synchronize across time zones". @@ -1106,7 +1106,8 @@ function Set-TargetResource How many units (minutes, hours, days) between each run of this task? .PARAMETER StartTime - The time of day this task should start at, or activate on - defaults to 12:00 AM. + The date and time of day this task should start at, or activate on, represented + as a string for local conversion to DateTime format - defaults to 1st January 1980 at 12:00 AM. .PARAMETER SynchronizeAcrossTimeZone Enable the scheduled task option to synchronize across time zones. This is enabled @@ -1311,8 +1312,8 @@ function Test-TargetResource $RepeatInterval = '00:00:00', [Parameter()] - [System.DateTime] - $StartTime = [System.DateTime]::Today, + [System.String] + $StartTime = [System.DateTime]::Parse("1980-01-01T00:00:00").ToString('s'), [Parameter()] [System.Boolean] @@ -1492,6 +1493,12 @@ function Test-TargetResource $currentValues = Get-CurrentResource -TaskName $TaskName -TaskPath $TaskPath + # Convert the strings containing dates & times to DateTime objects + if ($PSBoundParameters.ContainsKey('StartTime')) + { + $PSBoundParameters['StartTime'] = [System.DateTime]::Parse($StartTime) + } + # Convert the strings containing time spans to TimeSpan Objects if ($PSBoundParameters.ContainsKey('RepeatInterval')) { @@ -1569,7 +1576,7 @@ function Test-TargetResource $PSBoundParameters['StartTime'] = Get-DateTimeString -Date $StartTime -SynchronizeAcrossTimeZone $SynchronizeAcrossTimeZone <# If the current StartTime is null then we need to set it to - the desired StartTime (which defaults to Today if not passed) + the desired StartTime (which defaults to 1st January 1980 at 12:00 AM if not passed) so that the test does not fail. #> if ($currentValues['StartTime']) @@ -1877,7 +1884,7 @@ function Disable-ScheduledTaskEx The date to format. .PARAMETER SynchronizeAcrossTimeZone - Boolean to specifiy if the returned string is formatted in synchronize + Boolean to specify if the returned string is formatted in synchronize across time zone format. #> function Get-DateTimeString @@ -1894,18 +1901,16 @@ function Get-DateTimeString $SynchronizeAcrossTimeZone ) - $format = (Get-Culture).DateTimeFormat.SortableDateTimePattern - if ($SynchronizeAcrossTimeZone) { - $returnDate = (Get-Date -Date $Date -Format $format) + (Get-Date -Format 'zzz') + $format = (Get-Culture).DateTimeFormat.SortableDateTimePattern + 'zzz' } else { - $returnDate = Get-Date -Date $Date -Format $format + $format = (Get-Culture).DateTimeFormat.SortableDateTimePattern } - return $returnDate + return Get-Date -Date $Date -Format $format } <# @@ -2040,7 +2045,7 @@ function Get-CurrentResource if ($startAt) { $synchronizeAcrossTimeZone = Test-DateStringContainsTimeZone -DateString $startAt - $startTime = [System.DateTime] $startAt + $startTime = $startAt } else { @@ -2228,7 +2233,7 @@ function Test-DateStringContainsTimeZone $DateString ) - return $DateString.Contains('+') + return $DateString -match 'Z|\+' } <# diff --git a/source/DSCResources/DSC_ScheduledTask/DSC_ScheduledTask.schema.mof b/source/DSCResources/DSC_ScheduledTask/DSC_ScheduledTask.schema.mof index 7583fe4d..65b08f15 100644 --- a/source/DSCResources/DSC_ScheduledTask/DSC_ScheduledTask.schema.mof +++ b/source/DSCResources/DSC_ScheduledTask/DSC_ScheduledTask.schema.mof @@ -9,7 +9,7 @@ class DSC_ScheduledTask : OMI_BaseResource [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", "OnIdle", "OnEvent", "AtCreation", "OnSessionState"}, Values{"Once", "Daily", "Weekly", "AtStartup", "AtLogon", "OnIdle", "OnEvent", "AtCreation", "OnSessionState"}] 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, or activate on - defaults to 12:00 AM.")] DateTime StartTime; + [Write, Description("The date and time of day this task should start at, or activate on, represented as a string for local conversion to DateTime format - defaults to 1st January 1980 at 12:00 AM.")] String StartTime; [Write, Description("Enable the scheduled task option to synchronize across time zones. This is enabled by including the timezone offset in the scheduled task trigger. Defaults to false which does not include the timezone offset.")] boolean SynchronizeAcrossTimeZone; [Write, Description("Present if the task should exist, Absent if it should be removed."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] string Ensure; [Write, Description("True if the task should be enabled, false if it should be disabled.")] boolean Enable; diff --git a/source/DSCResources/DSC_ScheduledTask/README.md b/source/DSCResources/DSC_ScheduledTask/README.md index efc6df41..313ec691 100644 --- a/source/DSCResources/DSC_ScheduledTask/README.md +++ b/source/DSCResources/DSC_ScheduledTask/README.md @@ -6,6 +6,14 @@ scheduled tasks. ## Known Issues +When creating a scheduled task with a StartTime, you should always specify both +a date and a time, with the SortableDateTimePattern format (e.g. 1980-01-01T00:00:00). +Not providing a date may result in 'flip flopping' if the remote server enters daylight +savings time. The date and time specified will be set based on the time zone that has been +configured on the device. If you want to synchronize a scheduled task across timezones, +use the SynchronizeAcrossTimeZone parameter, and specify the timezone offset that is needed +(e.g. 1980-01-01T00:00:00-08:00). + One of the values needed for the `MultipleInstances` parameter is missing from the `Microsoft.PowerShell.Cmdletization.GeneratedTypes.ScheduledTask.MultipleInstancesEnum` enumerator. There are four valid values defined for the `MultipleInstances` property of the diff --git a/source/DSCResources/DSC_ScheduledTask/en-US/DSC_ScheduledTask.strings.psd1 b/source/DSCResources/DSC_ScheduledTask/en-US/DSC_ScheduledTask.strings.psd1 index 99ee4a03..9f8e0e4d 100644 --- a/source/DSCResources/DSC_ScheduledTask/en-US/DSC_ScheduledTask.strings.psd1 +++ b/source/DSCResources/DSC_ScheduledTask/en-US/DSC_ScheduledTask.strings.psd1 @@ -13,7 +13,6 @@ ConvertFrom-StringData @' OnEventSubscriptionError = No (valid) XML Event Subscription was provided. This is required when the scheduletype is OnEvent. OnSessionStateChangeError = No kind of session state change was provided. This is required when the scheduletype is OnSessionState. gMSAandCredentialError = Both ExecuteAsGMSA and (ExecuteAsCredential or BuiltInAccount) parameters have been specified. A task can run as a gMSA (Group Managed Service Account), a builtin service account or as a custom credential. Please modify your configuration to include just one of the three options. - SynchronizeAcrossTimeZoneInvalidScheduleType = Setting SynchronizeAcrossTimeZone to true when the ScheduleType is not Once, Daily or Weekly is not a valid configuration. Please keep the default value of false when using other schedule types. TriggerCreationError = Error creating new scheduled task trigger. ConfigureTriggerRepetitionMessage = Configuring trigger repetition. RepetitionIntervalError = Repetition interval is set to '{0}' but repetition duration is '{1}'. diff --git a/source/Examples/Resources/ScheduledTask/15-ScheduledTask_CreateScheduledTaskOnceSynchronizeAcrossTimeZoneEnabled_Config.ps1 b/source/Examples/Resources/ScheduledTask/15-ScheduledTask_CreateScheduledTaskOnceSynchronizeAcrossTimeZoneEnabled_Config.ps1 index 0b99012b..201d3f97 100644 --- a/source/Examples/Resources/ScheduledTask/15-ScheduledTask_CreateScheduledTaskOnceSynchronizeAcrossTimeZoneEnabled_Config.ps1 +++ b/source/Examples/Resources/ScheduledTask/15-ScheduledTask_CreateScheduledTaskOnceSynchronizeAcrossTimeZoneEnabled_Config.ps1 @@ -20,8 +20,8 @@ <# .DESCRIPTION This example creates a scheduled task called 'Test task sync across time zone enabled' - in the folder 'MyTasks' that starts a new powershell process once at 2018-10-01 01:00. - The task will have the option Synchronize across time zone enabled. + in the folder 'MyTasks' that starts a new powershell process once at 2018-10-01 01:00 + in the -08:00 timezone. The task will have the option Synchronize across time zone enabled. #> Configuration ScheduledTask_CreateScheduledTaskOnceSynchronizeAcrossTimeZoneEnabled_Config { @@ -35,7 +35,7 @@ Configuration ScheduledTask_CreateScheduledTaskOnceSynchronizeAcrossTimeZoneEnab TaskPath = '\MyTasks\' ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' ScheduleType = 'Once' - StartTime = '2018-10-01T01:00:00' + StartTime = '2018-10-01T01:00:00-08:00' SynchronizeAcrossTimeZone = $true ActionWorkingPath = (Get-Location).Path Enable = $true From 876a7acc92f19b34e2bbe0c0e389f5d3189c69f9 Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Tue, 26 Nov 2024 16:46:02 +0000 Subject: [PATCH 02/23] Update unit tests --- .../DSC_ScheduledTask.Integration.Tests.ps1 | 2 +- .../Integration/DSC_ScheduledTask.config.ps1 | 2 +- tests/Unit/DSC_ScheduledTask.Tests.ps1 | 42 +++++++------------ 3 files changed, 17 insertions(+), 29 deletions(-) diff --git a/tests/Integration/DSC_ScheduledTask.Integration.Tests.ps1 b/tests/Integration/DSC_ScheduledTask.Integration.Tests.ps1 index fdfc90c8..6059449a 100644 --- a/tests/Integration/DSC_ScheduledTask.Integration.Tests.ps1 +++ b/tests/Integration/DSC_ScheduledTask.Integration.Tests.ps1 @@ -349,7 +349,7 @@ Describe "$($script:dscResourceName)_Integration" { $configDir = (Join-Path -Path $TestDrive -ChildPath $currentConfig) $configMof = (Join-Path -Path $configDir -ChildPath 'localhost.mof') - $expectedStartTime = '2018-10-01T01:00:00' + (Get-Date -Format 'zzz') + $expectedStartTime = '2018-10-01T01:00:00-08:00' } AfterAll { diff --git a/tests/Integration/DSC_ScheduledTask.config.ps1 b/tests/Integration/DSC_ScheduledTask.config.ps1 index f0f11a3d..4b1ecf99 100644 --- a/tests/Integration/DSC_ScheduledTask.config.ps1 +++ b/tests/Integration/DSC_ScheduledTask.config.ps1 @@ -55,7 +55,7 @@ Configuration ScheduledTaskOnceSynchronizeAcrossTimeZoneEnabled TaskPath = '\ComputerManagementDsc\' ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' ScheduleType = 'Once' - StartTime = '2018-10-01T01:00:00' + StartTime = '2018-10-01T01:00:00-08:00' SynchronizeAcrossTimeZone = $true ActionWorkingPath = (Get-Location).Path Enable = $true diff --git a/tests/Unit/DSC_ScheduledTask.Tests.ps1 b/tests/Unit/DSC_ScheduledTask.Tests.ps1 index 4fe07fd3..88d2e7a8 100644 --- a/tests/Unit/DSC_ScheduledTask.Tests.ps1 +++ b/tests/Unit/DSC_ScheduledTask.Tests.ps1 @@ -2568,7 +2568,7 @@ Describe 'DSC_ScheduledTask' { ScheduleType = 'Once' } - $startTimeStringWithOffset = '2018-10-01T01:00:00' + (Get-Date -Format 'zzz') + $startTimeStringWithOffset = '2018-10-01T01:00:00-08:00' Mock -CommandName Get-ScheduledTask -MockWith { @{ @@ -2665,12 +2665,12 @@ Describe 'DSC_ScheduledTask' { Context 'When a scheduled task is created and synchronize across time zone is enabled' { BeforeDiscovery { - $startTimeStringWithOffset = '2018-10-01T01:00:00' + (Get-Date -Format 'zzz') + $startTimeStringWithOffset = '2018-10-01T01:00:00-08:00' } BeforeAll { $startTimeString = '2018-10-01T01:00:00' - $startTimeStringWithOffset = '2018-10-01T01:00:00' + (Get-Date -Format 'zzz') + $startTimeStringWithOffset = '2018-10-01T01:00:00-08:00' $testParameters = $getTargetResourceParameters + @{ ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' StartTime = Get-Date -Date $startTimeString @@ -2776,28 +2776,6 @@ Describe 'DSC_ScheduledTask' { } } - Context 'When a scheduled task is configured to SynchronizeAcrossTimeZone and the ScheduleType is not Once, Daily or Weekly' { - BeforeAll { - $startTimeString = '2018-10-01T01:00:00' - $testParameters = $getTargetResourceParameters + @{ - ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' - StartTime = Get-Date -Date $startTimeString - SynchronizeAcrossTimeZone = $true - ScheduleType = 'AtLogon' - } - } - - It 'Should throw when Set-TargetResource is called and SynchronizeAcrossTimeZone is used in combination with an unsupported trigger type' { - InModuleScope -ScriptBlock { - Set-StrictMode -Version 1.0 - - $errorRecord = Get-InvalidArgumentRecord -Message $LocalizedData.SynchronizeAcrossTimeZoneInvalidScheduleType -ArgumentName 'SynchronizeAcrossTimeZone' - - { Set-TargetResource @testParameters } | Should -Throw $errorRecord - } - } - } - Context 'When a scheduled task is configured with the ScheduleType AtLogon and is in desired state' { BeforeAll { $startTimeString = '2018-10-01T01:00:00' @@ -3455,12 +3433,22 @@ Describe 'DSC_ScheduledTask\Test-DateStringContainsTimeZone' -Tag 'Private' { } } - Context 'When the date string contains a date with a timezone' { + Context 'When the date string contains a date with a timezone offset' { + It 'Should return $true' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + Test-DateStringContainsTimeZone -DateString '2018-10-01T01:00:00-08:00' | Should -BeTrue + } + } + } + + Context 'When the date string contains a date with Zulu timezone' { It 'Should return $true' { InModuleScope -ScriptBlock { Set-StrictMode -Version 1.0 - Test-DateStringContainsTimeZone -DateString ('2018-10-01T01:00:00' + (Get-Date -Format 'zzz')) | Should -BeTrue + Test-DateStringContainsTimeZone -DateString '2018-10-01T01:00:00Z' | Should -BeTrue } } } From d7e5862a67de162cb549be76a1dbaa97623e87be Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Tue, 26 Nov 2024 16:49:48 +0000 Subject: [PATCH 03/23] Update Zulu description --- tests/Unit/DSC_ScheduledTask.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Unit/DSC_ScheduledTask.Tests.ps1 b/tests/Unit/DSC_ScheduledTask.Tests.ps1 index 88d2e7a8..baf87b43 100644 --- a/tests/Unit/DSC_ScheduledTask.Tests.ps1 +++ b/tests/Unit/DSC_ScheduledTask.Tests.ps1 @@ -3443,7 +3443,7 @@ Describe 'DSC_ScheduledTask\Test-DateStringContainsTimeZone' -Tag 'Private' { } } - Context 'When the date string contains a date with Zulu timezone' { + Context 'When the date string contains a date with Zulu timezone offset' { It 'Should return $true' { InModuleScope -ScriptBlock { Set-StrictMode -Version 1.0 From b9a2c9cbe2effa9168c73c948df57d671c88f0ba Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Tue, 26 Nov 2024 16:55:31 +0000 Subject: [PATCH 04/23] Remove unnecessary string --- tests/Unit/DSC_ScheduledTask.Tests.ps1 | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/Unit/DSC_ScheduledTask.Tests.ps1 b/tests/Unit/DSC_ScheduledTask.Tests.ps1 index baf87b43..11050a2b 100644 --- a/tests/Unit/DSC_ScheduledTask.Tests.ps1 +++ b/tests/Unit/DSC_ScheduledTask.Tests.ps1 @@ -2664,10 +2664,6 @@ Describe 'DSC_ScheduledTask' { } Context 'When a scheduled task is created and synchronize across time zone is enabled' { - BeforeDiscovery { - $startTimeStringWithOffset = '2018-10-01T01:00:00-08:00' - } - BeforeAll { $startTimeString = '2018-10-01T01:00:00' $startTimeStringWithOffset = '2018-10-01T01:00:00-08:00' From 324904c2ebc76d31aab869c650713c42c2c4e830 Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Tue, 26 Nov 2024 17:05:04 +0000 Subject: [PATCH 05/23] Restore startTimeStringWithOffset --- tests/Unit/DSC_ScheduledTask.Tests.ps1 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/Unit/DSC_ScheduledTask.Tests.ps1 b/tests/Unit/DSC_ScheduledTask.Tests.ps1 index 11050a2b..baf87b43 100644 --- a/tests/Unit/DSC_ScheduledTask.Tests.ps1 +++ b/tests/Unit/DSC_ScheduledTask.Tests.ps1 @@ -2664,6 +2664,10 @@ Describe 'DSC_ScheduledTask' { } Context 'When a scheduled task is created and synchronize across time zone is enabled' { + BeforeDiscovery { + $startTimeStringWithOffset = '2018-10-01T01:00:00-08:00' + } + BeforeAll { $startTimeString = '2018-10-01T01:00:00' $startTimeStringWithOffset = '2018-10-01T01:00:00-08:00' From b98dd70f0140676b9f5c382a744133fe917fb146 Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Tue, 26 Nov 2024 17:27:11 +0000 Subject: [PATCH 06/23] Fix negative UTC time strings --- CHANGELOG.md | 2 +- .../DSC_ScheduledTask/DSC_ScheduledTask.psm1 | 6 +- .../DSC_ScheduledTask.Integration.Tests.ps1 | 114 ++++++++- .../Integration/DSC_ScheduledTask.config.ps1 | 46 +++- tests/Unit/DSC_ScheduledTask.Tests.ps1 | 228 +++++++++++++++++- 5 files changed, 384 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ab8ffc0..0e9cdc37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - BREAKING CHANGE: ScheduledTask - Fixed SynchronizeAcrossTimeZone issue where Test always throws False when a date & time is used where Daylight Savings Time is in operation. Fixes [Issue #374](https://github.com/dsccommunity/ComputerManagementDsc/issues/374). + - Fixed Test-DateStringContainsTimeZone to process date strings behind UTC and UTC Zulu 'Z' strings. - Fixed User parameter to correctly return the user that triggers an AtLogon or OnSessionState Schedule Type, instead of the current value of ExecuteAsCredential. This parameter is only valid when using the AtLogon and OnSessionState Schedule Types. @@ -59,7 +60,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 Fixes [Issue #345](https://github.com/dsccommunity/ComputerManagementDsc/issues/345). - Updated User parameter for use with ScheduleType OnSessionState in addition to AtLogon. - Updated integration tests to ensure resource and configuration names are matching. - - Updated Test-DateStringContainsTimeZone to process with UTC date strings using Zulu 'Z' string. - Converted tests to Pester 5 - Rename Delete-ADSIObject to Delete-ADSIObject to satisfy HQRM diff --git a/source/DSCResources/DSC_ScheduledTask/DSC_ScheduledTask.psm1 b/source/DSCResources/DSC_ScheduledTask/DSC_ScheduledTask.psm1 index 73ebbbc3..3445b02c 100644 --- a/source/DSCResources/DSC_ScheduledTask/DSC_ScheduledTask.psm1 +++ b/source/DSCResources/DSC_ScheduledTask/DSC_ScheduledTask.psm1 @@ -303,7 +303,7 @@ function Set-TargetResource [Parameter()] [System.String] - $StartTime = [System.DateTime]::Parse("1980-01-01T00:00:00").ToString('s'), + $StartTime = '1980-01-01T00:00:00', [Parameter()] [System.Boolean] @@ -1313,7 +1313,7 @@ function Test-TargetResource [Parameter()] [System.String] - $StartTime = [System.DateTime]::Parse("1980-01-01T00:00:00").ToString('s'), + $StartTime = '1980-01-01T00:00:00', [Parameter()] [System.Boolean] @@ -2233,7 +2233,7 @@ function Test-DateStringContainsTimeZone $DateString ) - return $DateString -match 'Z|\+' + return $DateString -match '\+|-|Z' } <# diff --git a/tests/Integration/DSC_ScheduledTask.Integration.Tests.ps1 b/tests/Integration/DSC_ScheduledTask.Integration.Tests.ps1 index 6059449a..b1a92da9 100644 --- a/tests/Integration/DSC_ScheduledTask.Integration.Tests.ps1 +++ b/tests/Integration/DSC_ScheduledTask.Integration.Tests.ps1 @@ -343,9 +343,62 @@ Describe "$($script:dscResourceName)_Integration" { } } - Context 'When a scheduled task is created and synchronize across time zone is enabled' { + Context 'When a scheduled task is created and synchronize across time zone is enabled positive' { BeforeAll { - $currentConfig = 'ScheduledTaskOnceSynchronizeAcrossTimeZoneEnabled' + $currentConfig = 'ScheduledTaskOnceSynchronizeAcrossTimeZoneEnabledPositive' + $configDir = (Join-Path -Path $TestDrive -ChildPath $currentConfig) + $configMof = (Join-Path -Path $configDir -ChildPath 'localhost.mof') + + $expectedStartTime = '2018-10-01T01:00:00+08:00' + } + + AfterAll { + Wait-ForIdleLcm -Clear + } + + It 'Should compile the MOF without throwing' { + { + . $currentConfig ` + -OutputPath $configDir + } | Should -Not -Throw + } + + It 'Should apply the MOF correctly' { + { + Start-DscConfiguration ` + -Path $configDir ` + -Wait ` + -Force ` + -Verbose ` + -ErrorAction Stop + } | Should -Not -Throw + } + + It 'Should return a compliant state after being applied' { + (Test-DscConfiguration -ReferenceConfiguration $configMof -Verbose).InDesiredState | Should -BeTrue + } + + It 'Should have set the resource and all the parameters should match' { + $current = Get-DscConfiguration | Where-Object -FilterScript { $_.ConfigurationName -eq $currentConfig } + $current.TaskName | Should -Be 'Test task sync across time zone enabled positive' + $current.TaskPath | Should -Be '\ComputerManagementDsc\' + $current.ActionExecutable | Should -Be 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' + $current.ScheduleType | Should -Be 'Once' + $current.StartTime | Should -Be (Get-Date -Date $expectedStartTime) + $current.SynchronizeAcrossTimeZone | Should -BeTrue + $current.ActionWorkingPath | Should -Be (Get-Location).Path + $current.Enable | Should -BeTrue + } + + It 'Should have the trigger startBoundary set to ''2018-10-01T01:HH:MM''' { + $task = (Get-ScheduledTask -TaskName 'Test task sync across time zone enabled positive') + $task.Triggers[0].StartBoundary | Should -Be $expectedStartTime + } + } + + Context 'When a scheduled task is created and synchronize across time zone is enabled negative' { + BeforeAll { + $currentConfig = 'ScheduledTaskOnceSynchronizeAcrossTimeZoneEnabledNegative' $configDir = (Join-Path -Path $TestDrive -ChildPath $currentConfig) $configMof = (Join-Path -Path $configDir -ChildPath 'localhost.mof') @@ -380,7 +433,60 @@ Describe "$($script:dscResourceName)_Integration" { It 'Should have set the resource and all the parameters should match' { $current = Get-DscConfiguration | Where-Object -FilterScript { $_.ConfigurationName -eq $currentConfig } - $current.TaskName | Should -Be 'Test task sync across time zone enabled' + $current.TaskName | Should -Be 'Test task sync across time zone enabled negative' + $current.TaskPath | Should -Be '\ComputerManagementDsc\' + $current.ActionExecutable | Should -Be 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' + $current.ScheduleType | Should -Be 'Once' + $current.StartTime | Should -Be (Get-Date -Date $expectedStartTime) + $current.SynchronizeAcrossTimeZone | Should -BeTrue + $current.ActionWorkingPath | Should -Be (Get-Location).Path + $current.Enable | Should -BeTrue + } + + It 'Should have the trigger startBoundary set to ''2018-10-01T01:HH:MM''' { + $task = (Get-ScheduledTask -TaskName 'Test task sync across time zone enabled negative') + $task.Triggers[0].StartBoundary | Should -Be $expectedStartTime + } + } + + Context 'When a scheduled task is created and synchronize across time zone is enabled zulu' { + BeforeAll { + $currentConfig = 'ScheduledTaskOnceSynchronizeAcrossTimeZoneEnabledZulu' + $configDir = (Join-Path -Path $TestDrive -ChildPath $currentConfig) + $configMof = (Join-Path -Path $configDir -ChildPath 'localhost.mof') + + $expectedStartTime = '2018-10-01T01:00:00Z' + } + + AfterAll { + Wait-ForIdleLcm -Clear + } + + It 'Should compile the MOF without throwing' { + { + . $currentConfig ` + -OutputPath $configDir + } | Should -Not -Throw + } + + It 'Should apply the MOF correctly' { + { + Start-DscConfiguration ` + -Path $configDir ` + -Wait ` + -Force ` + -Verbose ` + -ErrorAction Stop + } | Should -Not -Throw + } + + It 'Should return a compliant state after being applied' { + (Test-DscConfiguration -ReferenceConfiguration $configMof -Verbose).InDesiredState | Should -BeTrue + } + + It 'Should have set the resource and all the parameters should match' { + $current = Get-DscConfiguration | Where-Object -FilterScript { $_.ConfigurationName -eq $currentConfig } + $current.TaskName | Should -Be 'Test task sync across time zone enabled zulu' $current.TaskPath | Should -Be '\ComputerManagementDsc\' $current.ActionExecutable | Should -Be 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' $current.ScheduleType | Should -Be 'Once' @@ -391,7 +497,7 @@ Describe "$($script:dscResourceName)_Integration" { } It 'Should have the trigger startBoundary set to ''2018-10-01T01:HH:MM''' { - $task = (Get-ScheduledTask -TaskName 'Test task sync across time zone enabled') + $task = (Get-ScheduledTask -TaskName 'Test task sync across time zone enabled zulu') $task.Triggers[0].StartBoundary | Should -Be $expectedStartTime } } diff --git a/tests/Integration/DSC_ScheduledTask.config.ps1 b/tests/Integration/DSC_ScheduledTask.config.ps1 index 4b1ecf99..2f269332 100644 --- a/tests/Integration/DSC_ScheduledTask.config.ps1 +++ b/tests/Integration/DSC_ScheduledTask.config.ps1 @@ -43,15 +43,35 @@ Configuration ScheduledTaskOnceSynchronizeAcrossTimeZoneDisabled } } -Configuration ScheduledTaskOnceSynchronizeAcrossTimeZoneEnabled +Configuration ScheduledTaskOnceSynchronizeAcrossTimeZoneEnabledPositive { Import-DscResource -ModuleName ComputerManagementDsc node 'localhost' { - ScheduledTask ScheduledTaskOnceSynchronizeAcrossTimeZoneEnabled + ScheduledTask ScheduledTaskOnceSynchronizeAcrossTimeZoneEnabledPositive { - TaskName = 'Test task sync across time zone enabled' + TaskName = 'Test task sync across time zone enabled positive' + TaskPath = '\ComputerManagementDsc\' + ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' + ScheduleType = 'Once' + StartTime = '2018-10-01T01:00:00+08:00' + SynchronizeAcrossTimeZone = $true + ActionWorkingPath = (Get-Location).Path + Enable = $true + } + } +} + +Configuration ScheduledTaskOnceSynchronizeAcrossTimeZoneEnabledNegative +{ + Import-DscResource -ModuleName ComputerManagementDsc + + node 'localhost' + { + ScheduledTask ScheduledTaskOnceSynchronizeAcrossTimeZoneEnabledNegative + { + TaskName = 'Test task sync across time zone enabled negative' TaskPath = '\ComputerManagementDsc\' ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' ScheduleType = 'Once' @@ -63,6 +83,26 @@ Configuration ScheduledTaskOnceSynchronizeAcrossTimeZoneEnabled } } +Configuration ScheduledTaskOnceSynchronizeAcrossTimeZoneEnabledZulu +{ + Import-DscResource -ModuleName ComputerManagementDsc + + node 'localhost' + { + ScheduledTask ScheduledTaskOnceSynchronizeAcrossTimeZoneEnabledZulu + { + TaskName = 'Test task sync across time zone enabled zulu' + TaskPath = '\ComputerManagementDsc\' + ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' + ScheduleType = 'Once' + StartTime = '2018-10-01T01:00:00Z' + SynchronizeAcrossTimeZone = $true + ActionWorkingPath = (Get-Location).Path + Enable = $true + } + } +} + Configuration ScheduledTaskOnceAdd { Import-DscResource -ModuleName ComputerManagementDsc diff --git a/tests/Unit/DSC_ScheduledTask.Tests.ps1 b/tests/Unit/DSC_ScheduledTask.Tests.ps1 index baf87b43..c89a2a81 100644 --- a/tests/Unit/DSC_ScheduledTask.Tests.ps1 +++ b/tests/Unit/DSC_ScheduledTask.Tests.ps1 @@ -2663,7 +2663,120 @@ Describe 'DSC_ScheduledTask' { } } - Context 'When a scheduled task is created and synchronize across time zone is enabled' { + Context 'When a scheduled task is created and synchronize across time zone is enabled positive' { + BeforeDiscovery { + $startTimeStringWithOffset = '2018-10-01T01:00:00+08:00' + } + + BeforeAll { + $startTimeString = '2018-10-01T01:00:00' + $startTimeStringWithOffset = '2018-10-01T01:00:00+08:00' + $testParameters = $getTargetResourceParameters + @{ + ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' + StartTime = Get-Date -Date $startTimeString + SynchronizeAcrossTimeZone = $true + ScheduleType = 'Once' + } + + InModuleScope -Parameters @{ + startTimeStringWithOffset = $startTimeStringWithOffset + } -ScriptBlock { + $script:startTimeStringWithOffset = $startTimeStringWithOffset + } + + Mock -CommandName Get-ScheduledTask -MockWith { + @{ + TaskName = $testParameters.TaskName + TaskPath = $testParameters.TaskPath + Actions = @( + [pscustomobject] @{ + Execute = $testParameters.ActionExecutable + } + ) + Triggers = @( + [pscustomobject] @{ + StartBoundary = $startTimeStringWithOffset + CimClass = @{ + CimClassName = 'MSFT_TaskTimeTrigger' + } + } + ) + Settings = [pscustomobject] @{ + Enabled = $true + MultipleInstances = 'IgnoreNew' + } + } + } + } + + It 'Should return the start time in DateTime format and SynchronizeAcrossTimeZone with value true' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $result = Get-TargetResource @getTargetResourceParameters + $result.StartTime | Should -Be (Get-Date -Date $startTimeStringWithOffset) + $result.SynchronizeAcrossTimeZone | Should -BeTrue + } + } + + It 'Should return true given that startTime is set correctly' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + Test-TargetResource @testParameters | Should -BeTrue + } + } + + Context 'When configured with synchronize across time zone disabled' { + BeforeAll { + Mock -CommandName Get-ScheduledTask -MockWith { + @{ + TaskName = $testParameters.TaskName + TaskPath = $testParameters.TaskPath + Actions = @( + [pscustomobject] @{ + Execute = $testParameters.ActionExecutable + } + ) + Triggers = @( + [pscustomobject] @{ + StartBoundary = $startTimeString + CimClass = @{ + CimClassName = 'MSFT_TaskTimeTrigger' + } + } + ) + Settings = [pscustomobject] @{ + Enabled = $true + MultipleInstances = 'IgnoreNew' + } + } + } + } + + It 'Should return false given that the task is configured with synchronize across time zone disabled' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + Test-TargetResource @testParameters | Should -BeFalse + } + } + + It "Should set task trigger StartBoundary to $startTimeStringWithOffset" { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + Set-TargetResource @testParameters + } + + Should -Invoke -CommandName Set-ScheduledTask -ParameterFilter { + $InputObject.Triggers[0].StartBoundary -eq $startTimeStringWithOffset + } + } + } + } + + Context 'When a scheduled task is created and synchronize across time zone is enabled negative' { BeforeDiscovery { $startTimeStringWithOffset = '2018-10-01T01:00:00-08:00' } @@ -2776,6 +2889,119 @@ Describe 'DSC_ScheduledTask' { } } + Context 'When a scheduled task is created and synchronize across time zone is enabled zulu' { + BeforeDiscovery { + $startTimeStringWithOffset = '2018-10-01T01:00:00-08:00Z' + } + + BeforeAll { + $startTimeString = '2018-10-01T01:00:00' + $startTimeStringWithOffset = '2018-10-01T01:00:00-08:00Z' + $testParameters = $getTargetResourceParameters + @{ + ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' + StartTime = Get-Date -Date $startTimeString + SynchronizeAcrossTimeZone = $true + ScheduleType = 'Once' + } + + InModuleScope -Parameters @{ + startTimeStringWithOffset = $startTimeStringWithOffset + } -ScriptBlock { + $script:startTimeStringWithOffset = $startTimeStringWithOffset + } + + Mock -CommandName Get-ScheduledTask -MockWith { + @{ + TaskName = $testParameters.TaskName + TaskPath = $testParameters.TaskPath + Actions = @( + [pscustomobject] @{ + Execute = $testParameters.ActionExecutable + } + ) + Triggers = @( + [pscustomobject] @{ + StartBoundary = $startTimeStringWithOffset + CimClass = @{ + CimClassName = 'MSFT_TaskTimeTrigger' + } + } + ) + Settings = [pscustomobject] @{ + Enabled = $true + MultipleInstances = 'IgnoreNew' + } + } + } + } + + It 'Should return the start time in DateTime format and SynchronizeAcrossTimeZone with value true' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $result = Get-TargetResource @getTargetResourceParameters + $result.StartTime | Should -Be (Get-Date -Date $startTimeStringWithOffset) + $result.SynchronizeAcrossTimeZone | Should -BeTrue + } + } + + It 'Should return true given that startTime is set correctly' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + Test-TargetResource @testParameters | Should -BeTrue + } + } + + Context 'When configured with synchronize across time zone disabled' { + BeforeAll { + Mock -CommandName Get-ScheduledTask -MockWith { + @{ + TaskName = $testParameters.TaskName + TaskPath = $testParameters.TaskPath + Actions = @( + [pscustomobject] @{ + Execute = $testParameters.ActionExecutable + } + ) + Triggers = @( + [pscustomobject] @{ + StartBoundary = $startTimeString + CimClass = @{ + CimClassName = 'MSFT_TaskTimeTrigger' + } + } + ) + Settings = [pscustomobject] @{ + Enabled = $true + MultipleInstances = 'IgnoreNew' + } + } + } + } + + It 'Should return false given that the task is configured with synchronize across time zone disabled' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + Test-TargetResource @testParameters | Should -BeFalse + } + } + + It "Should set task trigger StartBoundary to $startTimeStringWithOffset" { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + Set-TargetResource @testParameters + } + + Should -Invoke -CommandName Set-ScheduledTask -ParameterFilter { + $InputObject.Triggers[0].StartBoundary -eq $startTimeStringWithOffset + } + } + } + } + Context 'When a scheduled task is configured with the ScheduleType AtLogon and is in desired state' { BeforeAll { $startTimeString = '2018-10-01T01:00:00' From e7f0f8c5042764d58a174dff566cd89b037169f7 Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Tue, 26 Nov 2024 17:31:25 +0000 Subject: [PATCH 07/23] Update test --- tests/Integration/DSC_ScheduledTask.Integration.Tests.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Integration/DSC_ScheduledTask.Integration.Tests.ps1 b/tests/Integration/DSC_ScheduledTask.Integration.Tests.ps1 index b1a92da9..5c0fb42c 100644 --- a/tests/Integration/DSC_ScheduledTask.Integration.Tests.ps1 +++ b/tests/Integration/DSC_ScheduledTask.Integration.Tests.ps1 @@ -390,7 +390,7 @@ Describe "$($script:dscResourceName)_Integration" { $current.Enable | Should -BeTrue } - It 'Should have the trigger startBoundary set to ''2018-10-01T01:HH:MM''' { + It 'Should have the trigger startBoundary set to ''2018-10-01T01:00:00+08:00''' { $task = (Get-ScheduledTask -TaskName 'Test task sync across time zone enabled positive') $task.Triggers[0].StartBoundary | Should -Be $expectedStartTime } @@ -443,7 +443,7 @@ Describe "$($script:dscResourceName)_Integration" { $current.Enable | Should -BeTrue } - It 'Should have the trigger startBoundary set to ''2018-10-01T01:HH:MM''' { + It 'Should have the trigger startBoundary set to ''2018-10-01T01:00:00-08:00''' { $task = (Get-ScheduledTask -TaskName 'Test task sync across time zone enabled negative') $task.Triggers[0].StartBoundary | Should -Be $expectedStartTime } @@ -496,7 +496,7 @@ Describe "$($script:dscResourceName)_Integration" { $current.Enable | Should -BeTrue } - It 'Should have the trigger startBoundary set to ''2018-10-01T01:HH:MM''' { + It 'Should have the trigger startBoundary set to ''2018-10-01T01:00:00+00:00''' { $task = (Get-ScheduledTask -TaskName 'Test task sync across time zone enabled zulu') $task.Triggers[0].StartBoundary | Should -Be $expectedStartTime } From 9bc2aea8a5aefd9f3c1d31c763990c49c662294d Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Tue, 26 Nov 2024 17:47:41 +0000 Subject: [PATCH 08/23] Update tests --- .../DSC_ScheduledTask.Integration.Tests.ps1 | 8 +- tests/Unit/DSC_ScheduledTask.Tests.ps1 | 152 +++++++++++++++--- 2 files changed, 130 insertions(+), 30 deletions(-) diff --git a/tests/Integration/DSC_ScheduledTask.Integration.Tests.ps1 b/tests/Integration/DSC_ScheduledTask.Integration.Tests.ps1 index 5c0fb42c..c68a2f66 100644 --- a/tests/Integration/DSC_ScheduledTask.Integration.Tests.ps1 +++ b/tests/Integration/DSC_ScheduledTask.Integration.Tests.ps1 @@ -331,7 +331,7 @@ Describe "$($script:dscResourceName)_Integration" { $current.TaskPath | Should -Be '\ComputerManagementDsc\' $current.ActionExecutable | Should -Be 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' $current.ScheduleType | Should -Be 'Once' - $current.StartTime | Should -Be (Get-Date -Date $expectedStartTime) + $current.StartTime | Should -Be $expectedStartTime $current.SynchronizeAcrossTimeZone | Should -BeFalse $current.ActionWorkingPath | Should -Be (Get-Location).Path $current.Enable | Should -BeTrue @@ -384,7 +384,7 @@ Describe "$($script:dscResourceName)_Integration" { $current.TaskPath | Should -Be '\ComputerManagementDsc\' $current.ActionExecutable | Should -Be 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' $current.ScheduleType | Should -Be 'Once' - $current.StartTime | Should -Be (Get-Date -Date $expectedStartTime) + $current.StartTime | Should -Be $expectedStartTime $current.SynchronizeAcrossTimeZone | Should -BeTrue $current.ActionWorkingPath | Should -Be (Get-Location).Path $current.Enable | Should -BeTrue @@ -437,7 +437,7 @@ Describe "$($script:dscResourceName)_Integration" { $current.TaskPath | Should -Be '\ComputerManagementDsc\' $current.ActionExecutable | Should -Be 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' $current.ScheduleType | Should -Be 'Once' - $current.StartTime | Should -Be (Get-Date -Date $expectedStartTime) + $current.StartTime | Should -Be $expectedStartTime $current.SynchronizeAcrossTimeZone | Should -BeTrue $current.ActionWorkingPath | Should -Be (Get-Location).Path $current.Enable | Should -BeTrue @@ -490,7 +490,7 @@ Describe "$($script:dscResourceName)_Integration" { $current.TaskPath | Should -Be '\ComputerManagementDsc\' $current.ActionExecutable | Should -Be 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' $current.ScheduleType | Should -Be 'Once' - $current.StartTime | Should -Be (Get-Date -Date $expectedStartTime) + $current.StartTime | Should -Be $expectedStartTime $current.SynchronizeAcrossTimeZone | Should -BeTrue $current.ActionWorkingPath | Should -Be (Get-Location).Path $current.Enable | Should -BeTrue diff --git a/tests/Unit/DSC_ScheduledTask.Tests.ps1 b/tests/Unit/DSC_ScheduledTask.Tests.ps1 index c89a2a81..27cf9099 100644 --- a/tests/Unit/DSC_ScheduledTask.Tests.ps1 +++ b/tests/Unit/DSC_ScheduledTask.Tests.ps1 @@ -2563,12 +2563,14 @@ Describe 'DSC_ScheduledTask' { $startTimeString = '2018-10-01T01:00:00' $testParameters = $getTargetResourceParameters + @{ ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' - StartTime = Get-Date -Date $startTimeString + StartTime = $startTimeString SynchronizeAcrossTimeZone = $false ScheduleType = 'Once' } - $startTimeStringWithOffset = '2018-10-01T01:00:00-08:00' + $startTimeStringWithOffsetPositive = '2018-10-01T01:00:00+08:00' + $startTimeStringWithOffsetNegative = '2018-10-01T01:00:00-08:00' + $startTimeStringWithOffsetZulu = '2018-10-01T01:00:00Z' Mock -CommandName Get-ScheduledTask -MockWith { @{ @@ -2595,12 +2597,12 @@ Describe 'DSC_ScheduledTask' { } } - It 'Should return the start time in DateTime format and SynchronizeAcrossTimeZone with value false' { + It 'Should return the start time and SynchronizeAcrossTimeZone with value false' { InModuleScope -ScriptBlock { Set-StrictMode -Version 1.0 $result = Get-TargetResource @getTargetResourceParameters - $result.StartTime | Should -Be (Get-Date -Date $testParameters.StartTime) + $result.StartTime | Should -Be $testParameters.StartTime $result.SynchronizeAcrossTimeZone | Should -BeFalse } } @@ -2613,7 +2615,105 @@ Describe 'DSC_ScheduledTask' { } } - Context 'When task is configured across time zone' { + Context 'When task is configured across time zone positive' { + BeforeAll { + Mock -CommandName Get-ScheduledTask -MockWith { + @{ + TaskName = $testParameters.TaskName + TaskPath = $testParameters.TaskPath + Actions = @( + [pscustomobject] @{ + Execute = $testParameters.ActionExecutable + } + ) + Triggers = @( + [pscustomobject] @{ + StartBoundary = $startTimeStringWithOffsetPositive + CimClass = @{ + CimClassName = 'MSFT_TaskTimeTrigger' + } + } + ) + Settings = [pscustomobject] @{ + Enabled = $true + MultipleInstances = 'IgnoreNew' + } + } + } + } + + It 'Should return false given that the task is configured with synchronize across time zone' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + Test-TargetResource @testParameters | Should -BeFalse + } + } + + + It "Should set task trigger StartBoundary to $startTimeString" { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + Set-TargetResource @testParameters + } + + Should -Invoke -CommandName Set-ScheduledTask -ParameterFilter { + $InputObject.Triggers[0].StartBoundary -eq $startTimeString + } + } + } + + Context 'When task is configured across time zone negative' { + BeforeAll { + Mock -CommandName Get-ScheduledTask -MockWith { + @{ + TaskName = $testParameters.TaskName + TaskPath = $testParameters.TaskPath + Actions = @( + [pscustomobject] @{ + Execute = $testParameters.ActionExecutable + } + ) + Triggers = @( + [pscustomobject] @{ + StartBoundary = $startTimeStringWithOffsetNegative + CimClass = @{ + CimClassName = 'MSFT_TaskTimeTrigger' + } + } + ) + Settings = [pscustomobject] @{ + Enabled = $true + MultipleInstances = 'IgnoreNew' + } + } + } + } + + It 'Should return false given that the task is configured with synchronize across time zone' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + Test-TargetResource @testParameters | Should -BeFalse + } + } + + + It "Should set task trigger StartBoundary to $startTimeString" { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + Set-TargetResource @testParameters + } + + Should -Invoke -CommandName Set-ScheduledTask -ParameterFilter { + $InputObject.Triggers[0].StartBoundary -eq $startTimeString + } + } + } + + Context 'When task is configured across time zone zulu' { BeforeAll { Mock -CommandName Get-ScheduledTask -MockWith { @{ @@ -2626,7 +2726,7 @@ Describe 'DSC_ScheduledTask' { ) Triggers = @( [pscustomobject] @{ - StartBoundary = $startTimeStringWithOffset + StartBoundary = $startTimeStringWithOffsetZulu CimClass = @{ CimClassName = 'MSFT_TaskTimeTrigger' } @@ -2673,7 +2773,7 @@ Describe 'DSC_ScheduledTask' { $startTimeStringWithOffset = '2018-10-01T01:00:00+08:00' $testParameters = $getTargetResourceParameters + @{ ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' - StartTime = Get-Date -Date $startTimeString + StartTime = $startTimeString SynchronizeAcrossTimeZone = $true ScheduleType = 'Once' } @@ -2709,12 +2809,12 @@ Describe 'DSC_ScheduledTask' { } } - It 'Should return the start time in DateTime format and SynchronizeAcrossTimeZone with value true' { + It 'Should return the start time and SynchronizeAcrossTimeZone with value true' { InModuleScope -ScriptBlock { Set-StrictMode -Version 1.0 $result = Get-TargetResource @getTargetResourceParameters - $result.StartTime | Should -Be (Get-Date -Date $startTimeStringWithOffset) + $result.StartTime | Should -Be $startTimeStringWithOffset $result.SynchronizeAcrossTimeZone | Should -BeTrue } } @@ -2786,7 +2886,7 @@ Describe 'DSC_ScheduledTask' { $startTimeStringWithOffset = '2018-10-01T01:00:00-08:00' $testParameters = $getTargetResourceParameters + @{ ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' - StartTime = Get-Date -Date $startTimeString + StartTime = $startTimeString SynchronizeAcrossTimeZone = $true ScheduleType = 'Once' } @@ -2822,12 +2922,12 @@ Describe 'DSC_ScheduledTask' { } } - It 'Should return the start time in DateTime format and SynchronizeAcrossTimeZone with value true' { + It 'Should return the start time and SynchronizeAcrossTimeZone with value true' { InModuleScope -ScriptBlock { Set-StrictMode -Version 1.0 $result = Get-TargetResource @getTargetResourceParameters - $result.StartTime | Should -Be (Get-Date -Date $startTimeStringWithOffset) + $result.StartTime | Should -Be $startTimeStringWithOffset $result.SynchronizeAcrossTimeZone | Should -BeTrue } } @@ -2899,7 +2999,7 @@ Describe 'DSC_ScheduledTask' { $startTimeStringWithOffset = '2018-10-01T01:00:00-08:00Z' $testParameters = $getTargetResourceParameters + @{ ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' - StartTime = Get-Date -Date $startTimeString + StartTime = $startTimeString SynchronizeAcrossTimeZone = $true ScheduleType = 'Once' } @@ -2935,12 +3035,12 @@ Describe 'DSC_ScheduledTask' { } } - It 'Should return the start time in DateTime format and SynchronizeAcrossTimeZone with value true' { + It 'Should return the start time and SynchronizeAcrossTimeZone with value true' { InModuleScope -ScriptBlock { Set-StrictMode -Version 1.0 $result = Get-TargetResource @getTargetResourceParameters - $result.StartTime | Should -Be (Get-Date -Date $startTimeStringWithOffset) + $result.StartTime | Should -Be $startTimeStringWithOffset $result.SynchronizeAcrossTimeZone | Should -BeTrue } } @@ -3007,7 +3107,7 @@ Describe 'DSC_ScheduledTask' { $startTimeString = '2018-10-01T01:00:00' $testParameters = $getTargetResourceParameters + @{ ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' - StartTime = Get-Date -Date $startTimeString + StartTime = $startTimeString ScheduleType = 'AtLogon' User = 'MockedDomain\MockedUser' Delay = '00:01:00' @@ -3049,7 +3149,7 @@ Describe 'DSC_ScheduledTask' { $result = Get-TargetResource @getTargetResourceParameters $result.Enable | Should -Be $testParameters.Enable $result.Ensure | Should -Be 'Present' - $result.StartTime | Should -Be (Get-Date -Date $testParameters.StartTime) + $result.StartTime | Should -Be $testParameters.StartTime $result.ScheduleType | Should -Be $testParameters.ScheduleType $result.User | Should -Be $testParameters.User $result.Delay | Should -Be $testParameters.Delay @@ -3221,7 +3321,7 @@ Describe 'DSC_ScheduledTask' { $startTimeString = '2018-10-01T01:00:00' $testParameters = $getTargetResourceParameters + @{ ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' - StartTime = Get-Date -Date $startTimeString + StartTime = $startTimeString ScheduleType = 'OnIdle' Enable = $true } @@ -3258,7 +3358,7 @@ Describe 'DSC_ScheduledTask' { $result = Get-TargetResource @getTargetResourceParameters $result.Enable | Should -Be $testParameters.Enable $result.Ensure | Should -Be 'Present' - $result.StartTime | Should -Be (Get-Date -Date $testParameters.StartTime) + $result.StartTime | Should -Be $testParameters.StartTime $result.ScheduleType | Should -Be $testParameters.ScheduleType } } @@ -3277,7 +3377,7 @@ Describe 'DSC_ScheduledTask' { $startTimeString = '2018-10-01T01:00:00' $testParameters = $getTargetResourceParameters + @{ ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' - StartTime = Get-Date -Date $startTimeString + StartTime = $startTimeString ScheduleType = 'OnIdle' Enable = $true } @@ -3368,7 +3468,7 @@ Describe 'DSC_ScheduledTask' { $startTimeString = '2018-10-01T01:00:00' $testParameters = $getTargetResourceParameters + @{ ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' - StartTime = Get-Date -Date $startTimeString + StartTime = $startTimeString ScheduleType = 'AtCreation' Delay = '00:01:00' Enable = $true @@ -3407,7 +3507,7 @@ Describe 'DSC_ScheduledTask' { $result = Get-TargetResource @getTargetResourceParameters $result.Enable | Should -Be $testParameters.Enable $result.Ensure | Should -Be 'Present' - $result.StartTime | Should -Be (Get-Date -Date $testParameters.StartTime) + $result.StartTime | Should -Be $testParameters.StartTime $result.ScheduleType | Should -Be $testParameters.ScheduleType $result.Delay | Should -Be $testParameters.Delay } @@ -3427,7 +3527,7 @@ Describe 'DSC_ScheduledTask' { $startTimeString = '2018-10-01T01:00:00' $testParameters = $getTargetResourceParameters + @{ ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' - StartTime = Get-Date -Date $startTimeString + StartTime = $startTimeString ScheduleType = 'AtCreation' Delay = '00:01:00' Enable = $true @@ -3469,7 +3569,7 @@ Describe 'DSC_ScheduledTask' { $startTimeString = '2018-10-01T01:00:00' $testParameters = $getTargetResourceParameters + @{ ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' - StartTime = Get-Date -Date $startTimeString + StartTime = $startTimeString ScheduleType = 'OnSessionState' StateChange = 'OnConnectionFromLocalComputer' User = 'MockedDomain\MockedUser' @@ -3512,7 +3612,7 @@ Describe 'DSC_ScheduledTask' { $result = Get-TargetResource @getTargetResourceParameters $result.Enable | Should -Be $testParameters.Enable $result.Ensure | Should -Be 'Present' - $result.StartTime | Should -Be (Get-Date -Date $testParameters.StartTime) + $result.StartTime | Should -Be $testParameters.StartTime $result.ScheduleType | Should -Be $testParameters.ScheduleType $result.User | Should -Be $testParameters.User $result.StateChange | Should -Be $testParameters.StateChange @@ -3534,7 +3634,7 @@ Describe 'DSC_ScheduledTask' { $startTimeString = '2018-10-01T01:00:00' $testParameters = $getTargetResourceParameters + @{ ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' - StartTime = Get-Date -Date $startTimeString + StartTime = $startTimeString ScheduleType = 'OnSessionState' StateChange = 'OnConnectionFromLocalComputer' User = 'MockedDomain\MockedUser' From c73c008946fd6eb5d32459931fc51ebd0e916582 Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Tue, 26 Nov 2024 17:57:31 +0000 Subject: [PATCH 09/23] Fix UTC check for negative --- source/DSCResources/DSC_ScheduledTask/DSC_ScheduledTask.psm1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/DSCResources/DSC_ScheduledTask/DSC_ScheduledTask.psm1 b/source/DSCResources/DSC_ScheduledTask/DSC_ScheduledTask.psm1 index 3445b02c..a2171c1f 100644 --- a/source/DSCResources/DSC_ScheduledTask/DSC_ScheduledTask.psm1 +++ b/source/DSCResources/DSC_ScheduledTask/DSC_ScheduledTask.psm1 @@ -2233,7 +2233,8 @@ function Test-DateStringContainsTimeZone $DateString ) - return $DateString -match '\+|-|Z' + # String ends +HH:MM (ahead of UTC), or -HH:MM (behind UTC), or +00:00 (UTC), or Z (UTC) + return $DateString -match '((\+|-)\d\d:\d\d|Z)$' } <# From 4d2a97b2ef943ebcabfbbbfb1368e42da01b312b Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Tue, 26 Nov 2024 18:14:42 +0000 Subject: [PATCH 10/23] Fix tests --- .../DSC_ScheduledTask/DSC_ScheduledTask.psm1 | 5 +++-- tests/Unit/DSC_ScheduledTask.Tests.ps1 | 9 +++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/source/DSCResources/DSC_ScheduledTask/DSC_ScheduledTask.psm1 b/source/DSCResources/DSC_ScheduledTask/DSC_ScheduledTask.psm1 index a2171c1f..50eed6e4 100644 --- a/source/DSCResources/DSC_ScheduledTask/DSC_ScheduledTask.psm1 +++ b/source/DSCResources/DSC_ScheduledTask/DSC_ScheduledTask.psm1 @@ -2233,8 +2233,9 @@ function Test-DateStringContainsTimeZone $DateString ) - # String ends +HH:MM (ahead of UTC), or -HH:MM (behind UTC), or +00:00 (UTC), or Z (UTC) - return $DateString -match '((\+|-)\d\d:\d\d|Z)$' + # When parsing a DateTime, Kind will be 'Unspecified' unless parsed string includes time zone information + # See https://learn.microsoft.com/en-us/dotnet/api/system.datetime.parse?view=netframework-4.5#the-return-value-and-datetimekind + return [DateTime]::Parse($DateString).Kind -ne 'Unspecified' } <# diff --git a/tests/Unit/DSC_ScheduledTask.Tests.ps1 b/tests/Unit/DSC_ScheduledTask.Tests.ps1 index 27cf9099..ceb31114 100644 --- a/tests/Unit/DSC_ScheduledTask.Tests.ps1 +++ b/tests/Unit/DSC_ScheduledTask.Tests.ps1 @@ -2769,11 +2769,10 @@ Describe 'DSC_ScheduledTask' { } BeforeAll { - $startTimeString = '2018-10-01T01:00:00' $startTimeStringWithOffset = '2018-10-01T01:00:00+08:00' $testParameters = $getTargetResourceParameters + @{ ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' - StartTime = $startTimeString + StartTime = $startTimeStringWithOffset SynchronizeAcrossTimeZone = $true ScheduleType = 'Once' } @@ -2882,11 +2881,10 @@ Describe 'DSC_ScheduledTask' { } BeforeAll { - $startTimeString = '2018-10-01T01:00:00' $startTimeStringWithOffset = '2018-10-01T01:00:00-08:00' $testParameters = $getTargetResourceParameters + @{ ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' - StartTime = $startTimeString + StartTime = $startTimeStringWithOffset SynchronizeAcrossTimeZone = $true ScheduleType = 'Once' } @@ -2995,11 +2993,10 @@ Describe 'DSC_ScheduledTask' { } BeforeAll { - $startTimeString = '2018-10-01T01:00:00' $startTimeStringWithOffset = '2018-10-01T01:00:00-08:00Z' $testParameters = $getTargetResourceParameters + @{ ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' - StartTime = $startTimeString + StartTime = $startTimeStringWithOffset SynchronizeAcrossTimeZone = $true ScheduleType = 'Once' } From 43fa67b1be89e7ed401a11dafc8340061c184cc9 Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Thu, 28 Nov 2024 16:50:55 +0000 Subject: [PATCH 11/23] Fix tests --- tests/Unit/DSC_ScheduledTask.Tests.ps1 | 332 +------------------------ 1 file changed, 4 insertions(+), 328 deletions(-) diff --git a/tests/Unit/DSC_ScheduledTask.Tests.ps1 b/tests/Unit/DSC_ScheduledTask.Tests.ps1 index ceb31114..20bd0f2a 100644 --- a/tests/Unit/DSC_ScheduledTask.Tests.ps1 +++ b/tests/Unit/DSC_ScheduledTask.Tests.ps1 @@ -2568,9 +2568,7 @@ Describe 'DSC_ScheduledTask' { ScheduleType = 'Once' } - $startTimeStringWithOffsetPositive = '2018-10-01T01:00:00+08:00' - $startTimeStringWithOffsetNegative = '2018-10-01T01:00:00-08:00' - $startTimeStringWithOffsetZulu = '2018-10-01T01:00:00Z' + $startTimeStringWithOffset = '2018-10-01T01:00:00-08:00' Mock -CommandName Get-ScheduledTask -MockWith { @{ @@ -2615,7 +2613,7 @@ Describe 'DSC_ScheduledTask' { } } - Context 'When task is configured across time zone positive' { + Context 'When task is configured across time zone' { BeforeAll { Mock -CommandName Get-ScheduledTask -MockWith { @{ @@ -2664,223 +2662,13 @@ Describe 'DSC_ScheduledTask' { } } - Context 'When task is configured across time zone negative' { - BeforeAll { - Mock -CommandName Get-ScheduledTask -MockWith { - @{ - TaskName = $testParameters.TaskName - TaskPath = $testParameters.TaskPath - Actions = @( - [pscustomobject] @{ - Execute = $testParameters.ActionExecutable - } - ) - Triggers = @( - [pscustomobject] @{ - StartBoundary = $startTimeStringWithOffsetNegative - CimClass = @{ - CimClassName = 'MSFT_TaskTimeTrigger' - } - } - ) - Settings = [pscustomobject] @{ - Enabled = $true - MultipleInstances = 'IgnoreNew' - } - } - } - } - - It 'Should return false given that the task is configured with synchronize across time zone' { - InModuleScope -ScriptBlock { - Set-StrictMode -Version 1.0 - - Test-TargetResource @testParameters | Should -BeFalse - } - } - - - It "Should set task trigger StartBoundary to $startTimeString" { - InModuleScope -ScriptBlock { - Set-StrictMode -Version 1.0 - - Set-TargetResource @testParameters - } - - Should -Invoke -CommandName Set-ScheduledTask -ParameterFilter { - $InputObject.Triggers[0].StartBoundary -eq $startTimeString - } - } - } - - Context 'When task is configured across time zone zulu' { - BeforeAll { - Mock -CommandName Get-ScheduledTask -MockWith { - @{ - TaskName = $testParameters.TaskName - TaskPath = $testParameters.TaskPath - Actions = @( - [pscustomobject] @{ - Execute = $testParameters.ActionExecutable - } - ) - Triggers = @( - [pscustomobject] @{ - StartBoundary = $startTimeStringWithOffsetZulu - CimClass = @{ - CimClassName = 'MSFT_TaskTimeTrigger' - } - } - ) - Settings = [pscustomobject] @{ - Enabled = $true - MultipleInstances = 'IgnoreNew' - } - } - } - } - - It 'Should return false given that the task is configured with synchronize across time zone' { - InModuleScope -ScriptBlock { - Set-StrictMode -Version 1.0 - - Test-TargetResource @testParameters | Should -BeFalse - } - } - - - It "Should set task trigger StartBoundary to $startTimeString" { - InModuleScope -ScriptBlock { - Set-StrictMode -Version 1.0 - - Set-TargetResource @testParameters - } - - Should -Invoke -CommandName Set-ScheduledTask -ParameterFilter { - $InputObject.Triggers[0].StartBoundary -eq $startTimeString - } - } - } - } - - Context 'When a scheduled task is created and synchronize across time zone is enabled positive' { - BeforeDiscovery { - $startTimeStringWithOffset = '2018-10-01T01:00:00+08:00' - } - - BeforeAll { - $startTimeStringWithOffset = '2018-10-01T01:00:00+08:00' - $testParameters = $getTargetResourceParameters + @{ - ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' - StartTime = $startTimeStringWithOffset - SynchronizeAcrossTimeZone = $true - ScheduleType = 'Once' - } - - InModuleScope -Parameters @{ - startTimeStringWithOffset = $startTimeStringWithOffset - } -ScriptBlock { - $script:startTimeStringWithOffset = $startTimeStringWithOffset - } - - Mock -CommandName Get-ScheduledTask -MockWith { - @{ - TaskName = $testParameters.TaskName - TaskPath = $testParameters.TaskPath - Actions = @( - [pscustomobject] @{ - Execute = $testParameters.ActionExecutable - } - ) - Triggers = @( - [pscustomobject] @{ - StartBoundary = $startTimeStringWithOffset - CimClass = @{ - CimClassName = 'MSFT_TaskTimeTrigger' - } - } - ) - Settings = [pscustomobject] @{ - Enabled = $true - MultipleInstances = 'IgnoreNew' - } - } - } - } - - It 'Should return the start time and SynchronizeAcrossTimeZone with value true' { - InModuleScope -ScriptBlock { - Set-StrictMode -Version 1.0 - - $result = Get-TargetResource @getTargetResourceParameters - $result.StartTime | Should -Be $startTimeStringWithOffset - $result.SynchronizeAcrossTimeZone | Should -BeTrue - } - } - - It 'Should return true given that startTime is set correctly' { - InModuleScope -ScriptBlock { - Set-StrictMode -Version 1.0 - - Test-TargetResource @testParameters | Should -BeTrue - } - } - - Context 'When configured with synchronize across time zone disabled' { - BeforeAll { - Mock -CommandName Get-ScheduledTask -MockWith { - @{ - TaskName = $testParameters.TaskName - TaskPath = $testParameters.TaskPath - Actions = @( - [pscustomobject] @{ - Execute = $testParameters.ActionExecutable - } - ) - Triggers = @( - [pscustomobject] @{ - StartBoundary = $startTimeString - CimClass = @{ - CimClassName = 'MSFT_TaskTimeTrigger' - } - } - ) - Settings = [pscustomobject] @{ - Enabled = $true - MultipleInstances = 'IgnoreNew' - } - } - } - } - - It 'Should return false given that the task is configured with synchronize across time zone disabled' { - InModuleScope -ScriptBlock { - Set-StrictMode -Version 1.0 - - Test-TargetResource @testParameters | Should -BeFalse - } - } - - It "Should set task trigger StartBoundary to $startTimeStringWithOffset" { - InModuleScope -ScriptBlock { - Set-StrictMode -Version 1.0 - - Set-TargetResource @testParameters - } - - Should -Invoke -CommandName Set-ScheduledTask -ParameterFilter { - $InputObject.Triggers[0].StartBoundary -eq $startTimeStringWithOffset - } - } - } - } - - Context 'When a scheduled task is created and synchronize across time zone is enabled negative' { + Context 'When a scheduled task is created and synchronize across time zone is enabled' { BeforeDiscovery { $startTimeStringWithOffset = '2018-10-01T01:00:00-08:00' } BeforeAll { + $startTimeString = '2018-10-01T01:00:00' $startTimeStringWithOffset = '2018-10-01T01:00:00-08:00' $testParameters = $getTargetResourceParameters + @{ ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' @@ -2987,118 +2775,6 @@ Describe 'DSC_ScheduledTask' { } } - Context 'When a scheduled task is created and synchronize across time zone is enabled zulu' { - BeforeDiscovery { - $startTimeStringWithOffset = '2018-10-01T01:00:00-08:00Z' - } - - BeforeAll { - $startTimeStringWithOffset = '2018-10-01T01:00:00-08:00Z' - $testParameters = $getTargetResourceParameters + @{ - ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' - StartTime = $startTimeStringWithOffset - SynchronizeAcrossTimeZone = $true - ScheduleType = 'Once' - } - - InModuleScope -Parameters @{ - startTimeStringWithOffset = $startTimeStringWithOffset - } -ScriptBlock { - $script:startTimeStringWithOffset = $startTimeStringWithOffset - } - - Mock -CommandName Get-ScheduledTask -MockWith { - @{ - TaskName = $testParameters.TaskName - TaskPath = $testParameters.TaskPath - Actions = @( - [pscustomobject] @{ - Execute = $testParameters.ActionExecutable - } - ) - Triggers = @( - [pscustomobject] @{ - StartBoundary = $startTimeStringWithOffset - CimClass = @{ - CimClassName = 'MSFT_TaskTimeTrigger' - } - } - ) - Settings = [pscustomobject] @{ - Enabled = $true - MultipleInstances = 'IgnoreNew' - } - } - } - } - - It 'Should return the start time and SynchronizeAcrossTimeZone with value true' { - InModuleScope -ScriptBlock { - Set-StrictMode -Version 1.0 - - $result = Get-TargetResource @getTargetResourceParameters - $result.StartTime | Should -Be $startTimeStringWithOffset - $result.SynchronizeAcrossTimeZone | Should -BeTrue - } - } - - It 'Should return true given that startTime is set correctly' { - InModuleScope -ScriptBlock { - Set-StrictMode -Version 1.0 - - Test-TargetResource @testParameters | Should -BeTrue - } - } - - Context 'When configured with synchronize across time zone disabled' { - BeforeAll { - Mock -CommandName Get-ScheduledTask -MockWith { - @{ - TaskName = $testParameters.TaskName - TaskPath = $testParameters.TaskPath - Actions = @( - [pscustomobject] @{ - Execute = $testParameters.ActionExecutable - } - ) - Triggers = @( - [pscustomobject] @{ - StartBoundary = $startTimeString - CimClass = @{ - CimClassName = 'MSFT_TaskTimeTrigger' - } - } - ) - Settings = [pscustomobject] @{ - Enabled = $true - MultipleInstances = 'IgnoreNew' - } - } - } - } - - It 'Should return false given that the task is configured with synchronize across time zone disabled' { - InModuleScope -ScriptBlock { - Set-StrictMode -Version 1.0 - - Test-TargetResource @testParameters | Should -BeFalse - } - } - - It "Should set task trigger StartBoundary to $startTimeStringWithOffset" { - InModuleScope -ScriptBlock { - Set-StrictMode -Version 1.0 - - Set-TargetResource @testParameters - } - - Should -Invoke -CommandName Set-ScheduledTask -ParameterFilter { - $InputObject.Triggers[0].StartBoundary -eq $startTimeStringWithOffset - } - } - } - } - Context 'When a scheduled task is configured with the ScheduleType AtLogon and is in desired state' { BeforeAll { $startTimeString = '2018-10-01T01:00:00' From f14a184a64cca5470b8d3ab6c5d6bca64bbec833 Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Thu, 28 Nov 2024 16:53:42 +0000 Subject: [PATCH 12/23] Update tests --- tests/Unit/DSC_ScheduledTask.Tests.ps1 | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/tests/Unit/DSC_ScheduledTask.Tests.ps1 b/tests/Unit/DSC_ScheduledTask.Tests.ps1 index 20bd0f2a..bab61560 100644 --- a/tests/Unit/DSC_ScheduledTask.Tests.ps1 +++ b/tests/Unit/DSC_ScheduledTask.Tests.ps1 @@ -2626,7 +2626,7 @@ Describe 'DSC_ScheduledTask' { ) Triggers = @( [pscustomobject] @{ - StartBoundary = $startTimeStringWithOffsetPositive + StartBoundary = $startTimeStringWithOffset CimClass = @{ CimClassName = 'MSFT_TaskTimeTrigger' } @@ -2672,7 +2672,7 @@ Describe 'DSC_ScheduledTask' { $startTimeStringWithOffset = '2018-10-01T01:00:00-08:00' $testParameters = $getTargetResourceParameters + @{ ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' - StartTime = $startTimeStringWithOffset + StartTime = $startTimeString SynchronizeAcrossTimeZone = $true ScheduleType = 'Once' } @@ -3432,7 +3432,7 @@ Describe 'DSC_ScheduledTask\Test-DateStringContainsTimeZone' -Tag 'Private' { } } - Context 'When the date string contains a date with a timezone offset' { + Context 'When the date string contains a date with a negative timezone offset' { It 'Should return $true' { InModuleScope -ScriptBlock { Set-StrictMode -Version 1.0 @@ -3442,6 +3442,16 @@ Describe 'DSC_ScheduledTask\Test-DateStringContainsTimeZone' -Tag 'Private' { } } + Context 'When the date string contains a date with a positive timezone offset' { + It 'Should return $true' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + Test-DateStringContainsTimeZone -DateString '2018-10-01T01:00:00+08:00' | Should -BeTrue + } + } + } + Context 'When the date string contains a date with Zulu timezone offset' { It 'Should return $true' { InModuleScope -ScriptBlock { From 469305eeb11e4d48c6a8c450c0042a631e96b1c8 Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Thu, 28 Nov 2024 17:05:24 +0000 Subject: [PATCH 13/23] Fix bracket --- tests/Unit/DSC_ScheduledTask.Tests.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Unit/DSC_ScheduledTask.Tests.ps1 b/tests/Unit/DSC_ScheduledTask.Tests.ps1 index bab61560..cec969d2 100644 --- a/tests/Unit/DSC_ScheduledTask.Tests.ps1 +++ b/tests/Unit/DSC_ScheduledTask.Tests.ps1 @@ -2661,6 +2661,7 @@ Describe 'DSC_ScheduledTask' { } } } + } Context 'When a scheduled task is created and synchronize across time zone is enabled' { BeforeDiscovery { From 0f4dd45366427b95ee42127b3f1d5bded80aec13 Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Thu, 28 Nov 2024 17:25:19 +0000 Subject: [PATCH 14/23] Fix test --- tests/Unit/DSC_ScheduledTask.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Unit/DSC_ScheduledTask.Tests.ps1 b/tests/Unit/DSC_ScheduledTask.Tests.ps1 index cec969d2..5b8bd6f9 100644 --- a/tests/Unit/DSC_ScheduledTask.Tests.ps1 +++ b/tests/Unit/DSC_ScheduledTask.Tests.ps1 @@ -2673,7 +2673,7 @@ Describe 'DSC_ScheduledTask' { $startTimeStringWithOffset = '2018-10-01T01:00:00-08:00' $testParameters = $getTargetResourceParameters + @{ ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' - StartTime = $startTimeString + StartTime = $startTimeStringWithOffset SynchronizeAcrossTimeZone = $true ScheduleType = 'Once' } From d3f72d4c06ce00206d0abfe4793f036459d39208 Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Thu, 28 Nov 2024 17:29:45 +0000 Subject: [PATCH 15/23] Update change log --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e9cdc37..3dedae19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,7 +27,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - BREAKING CHANGE: ScheduledTask - Fixed SynchronizeAcrossTimeZone issue where Test always throws False when a date & time is used where Daylight Savings Time is in operation. Fixes [Issue #374](https://github.com/dsccommunity/ComputerManagementDsc/issues/374). - - Fixed Test-DateStringContainsTimeZone to process date strings behind UTC and UTC Zulu 'Z' strings. + - Fixed Test-DateStringContainsTimeZone to correctly process date strings behind UTC (-), as well + as UTC Zulu 'Z' strings. - Fixed User parameter to correctly return the user that triggers an AtLogon or OnSessionState Schedule Type, instead of the current value of ExecuteAsCredential. This parameter is only valid when using the AtLogon and OnSessionState Schedule Types. From 17b8c464086a6ad6362c5c4ff37647a26d885a6f Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Thu, 28 Nov 2024 17:59:10 +0000 Subject: [PATCH 16/23] Update tests --- .../Integration/DSC_ScheduledTask.Integration.Tests.ps1 | 9 ++++++--- tests/Unit/DSC_ScheduledTask.Tests.ps1 | 3 ++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/Integration/DSC_ScheduledTask.Integration.Tests.ps1 b/tests/Integration/DSC_ScheduledTask.Integration.Tests.ps1 index c68a2f66..2aefbe5d 100644 --- a/tests/Integration/DSC_ScheduledTask.Integration.Tests.ps1 +++ b/tests/Integration/DSC_ScheduledTask.Integration.Tests.ps1 @@ -349,7 +349,8 @@ Describe "$($script:dscResourceName)_Integration" { $configDir = (Join-Path -Path $TestDrive -ChildPath $currentConfig) $configMof = (Join-Path -Path $configDir -ChildPath 'localhost.mof') - $expectedStartTime = '2018-10-01T01:00:00+08:00' + $configuredStartTime = '2018-10-01T01:00:00+08:00' + $expectedStartTime = (Get-Date -Date $configuredStartTime).ToUniversalTime().ToString((Get-Culture).DateTimeFormat.SortableDateTimePattern + 'zzz') } AfterAll { @@ -402,7 +403,8 @@ Describe "$($script:dscResourceName)_Integration" { $configDir = (Join-Path -Path $TestDrive -ChildPath $currentConfig) $configMof = (Join-Path -Path $configDir -ChildPath 'localhost.mof') - $expectedStartTime = '2018-10-01T01:00:00-08:00' + $configuredStartTime = '2018-10-01T01:00:00-08:00' + $expectedStartTime = (Get-Date -Date $configuredStartTime).ToUniversalTime().ToString((Get-Culture).DateTimeFormat.SortableDateTimePattern + 'zzz') } AfterAll { @@ -455,7 +457,8 @@ Describe "$($script:dscResourceName)_Integration" { $configDir = (Join-Path -Path $TestDrive -ChildPath $currentConfig) $configMof = (Join-Path -Path $configDir -ChildPath 'localhost.mof') - $expectedStartTime = '2018-10-01T01:00:00Z' + $configuredStartTime = '2018-10-01T01:00:00Z' + $expectedStartTime = (Get-Date -Date $configuredStartTime).ToUniversalTime().ToString((Get-Culture).DateTimeFormat.SortableDateTimePattern + 'zzz') } AfterAll { diff --git a/tests/Unit/DSC_ScheduledTask.Tests.ps1 b/tests/Unit/DSC_ScheduledTask.Tests.ps1 index 5b8bd6f9..9fe47eac 100644 --- a/tests/Unit/DSC_ScheduledTask.Tests.ps1 +++ b/tests/Unit/DSC_ScheduledTask.Tests.ps1 @@ -2671,6 +2671,7 @@ Describe 'DSC_ScheduledTask' { BeforeAll { $startTimeString = '2018-10-01T01:00:00' $startTimeStringWithOffset = '2018-10-01T01:00:00-08:00' + $expectedStartTimeStringWithOffset = (Get-Date -Date $startTimeStringWithOffset).ToUniversalTime().ToString((Get-Culture).DateTimeFormat.SortableDateTimePattern + 'zzz') $testParameters = $getTargetResourceParameters + @{ ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' StartTime = $startTimeStringWithOffset @@ -2770,7 +2771,7 @@ Describe 'DSC_ScheduledTask' { } Should -Invoke -CommandName Set-ScheduledTask -ParameterFilter { - $InputObject.Triggers[0].StartBoundary -eq $startTimeStringWithOffset + $InputObject.Triggers[0].StartBoundary -eq $expectedStartTimeStringWithOffset } } } From 4f119503d494a6b99ec995ef606a4c01fba1c56f Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Thu, 28 Nov 2024 18:12:08 +0000 Subject: [PATCH 17/23] Fix expected offsets --- tests/Unit/DSC_ScheduledTask.Tests.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Unit/DSC_ScheduledTask.Tests.ps1 b/tests/Unit/DSC_ScheduledTask.Tests.ps1 index 9fe47eac..d482d790 100644 --- a/tests/Unit/DSC_ScheduledTask.Tests.ps1 +++ b/tests/Unit/DSC_ScheduledTask.Tests.ps1 @@ -2696,7 +2696,7 @@ Describe 'DSC_ScheduledTask' { ) Triggers = @( [pscustomobject] @{ - StartBoundary = $startTimeStringWithOffset + StartBoundary = $expectedStartTimeStringWithOffset CimClass = @{ CimClassName = 'MSFT_TaskTimeTrigger' } @@ -2715,7 +2715,7 @@ Describe 'DSC_ScheduledTask' { Set-StrictMode -Version 1.0 $result = Get-TargetResource @getTargetResourceParameters - $result.StartTime | Should -Be $startTimeStringWithOffset + $result.StartTime | Should -Be $expectedStartTimeStringWithOffset $result.SynchronizeAcrossTimeZone | Should -BeTrue } } @@ -2763,7 +2763,7 @@ Describe 'DSC_ScheduledTask' { } } - It "Should set task trigger StartBoundary to $startTimeStringWithOffset" { + It "Should set task trigger StartBoundary to $expectedStartTimeStringWithOffset" { InModuleScope -ScriptBlock { Set-StrictMode -Version 1.0 From b3ecc90d461ef715b844e2d45fc912fccea31231 Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Thu, 28 Nov 2024 18:17:28 +0000 Subject: [PATCH 18/23] Put everything through UTC - PowerShell does anyway... --- .../DSCResources/DSC_ScheduledTask/DSC_ScheduledTask.psm1 | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/source/DSCResources/DSC_ScheduledTask/DSC_ScheduledTask.psm1 b/source/DSCResources/DSC_ScheduledTask/DSC_ScheduledTask.psm1 index 50eed6e4..223c9ef3 100644 --- a/source/DSCResources/DSC_ScheduledTask/DSC_ScheduledTask.psm1 +++ b/source/DSCResources/DSC_ScheduledTask/DSC_ScheduledTask.psm1 @@ -1903,14 +1903,18 @@ function Get-DateTimeString if ($SynchronizeAcrossTimeZone) { - $format = (Get-Culture).DateTimeFormat.SortableDateTimePattern + 'zzz' + # Synchronize across times zones internally ends up storing the date in UTC (Zulu) form + # https://www.thecliguy.co.uk/2020/02/09/scheduled-task-trigger-synchronize-across-time-zones/ + $format = (Get-Culture).DateTimeFormat.UniversalSortableDateTimePattern + $returnDate = Get-Date -Date $Date.ToUniversalTime() -Format $format } else { $format = (Get-Culture).DateTimeFormat.SortableDateTimePattern + $returnDate = Get-Date -Date $Date -Format $format } - return Get-Date -Date $Date -Format $format + return $returnDate } <# From 810d7eb960edd94ab28a8ce74dbbd3a2bb7ebb8a Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Fri, 29 Nov 2024 13:36:49 +0000 Subject: [PATCH 19/23] Set sortable date time pattern w/ local time correctly --- .../DSCResources/DSC_ScheduledTask/DSC_ScheduledTask.psm1 | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/source/DSCResources/DSC_ScheduledTask/DSC_ScheduledTask.psm1 b/source/DSCResources/DSC_ScheduledTask/DSC_ScheduledTask.psm1 index 223c9ef3..488f2373 100644 --- a/source/DSCResources/DSC_ScheduledTask/DSC_ScheduledTask.psm1 +++ b/source/DSCResources/DSC_ScheduledTask/DSC_ScheduledTask.psm1 @@ -1903,10 +1903,8 @@ function Get-DateTimeString if ($SynchronizeAcrossTimeZone) { - # Synchronize across times zones internally ends up storing the date in UTC (Zulu) form - # https://www.thecliguy.co.uk/2020/02/09/scheduled-task-trigger-synchronize-across-time-zones/ - $format = (Get-Culture).DateTimeFormat.UniversalSortableDateTimePattern - $returnDate = Get-Date -Date $Date.ToUniversalTime() -Format $format + $format = (Get-Culture).DateTimeFormat.SortableDateTimePattern + 'zzz' + $returnDate = Get-Date -Date $Date.ToLocalTime() -Format $format } else { From ac232f2cc7f9a4364b72f22f5a7e82966b124339 Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Fri, 29 Nov 2024 13:51:33 +0000 Subject: [PATCH 20/23] Fix test --- tests/Unit/DSC_ScheduledTask.Tests.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Unit/DSC_ScheduledTask.Tests.ps1 b/tests/Unit/DSC_ScheduledTask.Tests.ps1 index d482d790..0cca3e20 100644 --- a/tests/Unit/DSC_ScheduledTask.Tests.ps1 +++ b/tests/Unit/DSC_ScheduledTask.Tests.ps1 @@ -2666,6 +2666,7 @@ Describe 'DSC_ScheduledTask' { Context 'When a scheduled task is created and synchronize across time zone is enabled' { BeforeDiscovery { $startTimeStringWithOffset = '2018-10-01T01:00:00-08:00' + $expectedStartTimeStringWithOffset = (Get-Date -Date $startTimeStringWithOffset).ToUniversalTime().ToString((Get-Culture).DateTimeFormat.SortableDateTimePattern + 'zzz') } BeforeAll { From f369f8ecd9dc9684bb84c9d1aa8dd6da0ac500e7 Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Fri, 29 Nov 2024 14:01:01 +0000 Subject: [PATCH 21/23] Fix test --- tests/Unit/DSC_ScheduledTask.Tests.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Unit/DSC_ScheduledTask.Tests.ps1 b/tests/Unit/DSC_ScheduledTask.Tests.ps1 index 0cca3e20..583ead7d 100644 --- a/tests/Unit/DSC_ScheduledTask.Tests.ps1 +++ b/tests/Unit/DSC_ScheduledTask.Tests.ps1 @@ -2681,9 +2681,9 @@ Describe 'DSC_ScheduledTask' { } InModuleScope -Parameters @{ - startTimeStringWithOffset = $startTimeStringWithOffset + expectedStartTimeStringWithOffset = $expectedStartTimeStringWithOffset } -ScriptBlock { - $script:startTimeStringWithOffset = $startTimeStringWithOffset + $script:expectedStartTimeStringWithOffset = $expectedStartTimeStringWithOffset } Mock -CommandName Get-ScheduledTask -MockWith { From b4f12201e6624156cf93dbc3e9a27577d9abb525 Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Fri, 29 Nov 2024 14:22:06 +0000 Subject: [PATCH 22/23] Add expected start time to Pester test names --- .../DSC_ScheduledTask.Integration.Tests.ps1 | 51 +++++++++++++++++-- tests/Unit/DSC_ScheduledTask.Tests.ps1 | 14 ++++- 2 files changed, 59 insertions(+), 6 deletions(-) diff --git a/tests/Integration/DSC_ScheduledTask.Integration.Tests.ps1 b/tests/Integration/DSC_ScheduledTask.Integration.Tests.ps1 index 2aefbe5d..f2c353b3 100644 --- a/tests/Integration/DSC_ScheduledTask.Integration.Tests.ps1 +++ b/tests/Integration/DSC_ScheduledTask.Integration.Tests.ps1 @@ -291,12 +291,22 @@ Describe "$($script:dscResourceName)_Integration" { } Context 'When a scheduled task is created and synchronize across time zone is disabled' { + BeforeDiscovery { + $expectedStartTime = '2018-10-01T01:00:00' + } + BeforeAll { $currentConfig = 'ScheduledTaskOnceSynchronizeAcrossTimeZoneDisabled' $configDir = (Join-Path -Path $TestDrive -ChildPath $currentConfig) $configMof = (Join-Path -Path $configDir -ChildPath 'localhost.mof') $expectedStartTime = '2018-10-01T01:00:00' + + InModuleScope -Parameters @{ + expectedStartTime = $expectedStartTime + } -ScriptBlock { + $script:expectedStartTime = $expectedStartTime + } } AfterAll { @@ -337,13 +347,18 @@ Describe "$($script:dscResourceName)_Integration" { $current.Enable | Should -BeTrue } - It 'Should have the trigger startBoundary set to ''2018-10-01T01:00:00''' { + It "Should have the trigger startBoundary set to '$expectedStartTime'" { $task = (Get-ScheduledTask -TaskName 'Test task sync across time zone disabled') $task.Triggers[0].StartBoundary | Should -Be $expectedStartTime } } Context 'When a scheduled task is created and synchronize across time zone is enabled positive' { + BeforeDiscovery { + $configuredStartTime = '2018-10-01T01:00:00+08:00' + $expectedStartTime = (Get-Date -Date $configuredStartTime).ToUniversalTime().ToString((Get-Culture).DateTimeFormat.SortableDateTimePattern + 'zzz') + } + BeforeAll { $currentConfig = 'ScheduledTaskOnceSynchronizeAcrossTimeZoneEnabledPositive' $configDir = (Join-Path -Path $TestDrive -ChildPath $currentConfig) @@ -351,6 +366,12 @@ Describe "$($script:dscResourceName)_Integration" { $configuredStartTime = '2018-10-01T01:00:00+08:00' $expectedStartTime = (Get-Date -Date $configuredStartTime).ToUniversalTime().ToString((Get-Culture).DateTimeFormat.SortableDateTimePattern + 'zzz') + + InModuleScope -Parameters @{ + expectedStartTime = $expectedStartTime + } -ScriptBlock { + $script:expectedStartTime = $expectedStartTime + } } AfterAll { @@ -391,13 +412,18 @@ Describe "$($script:dscResourceName)_Integration" { $current.Enable | Should -BeTrue } - It 'Should have the trigger startBoundary set to ''2018-10-01T01:00:00+08:00''' { + It "Should have the trigger startBoundary set to '$expectedStartTime'" { $task = (Get-ScheduledTask -TaskName 'Test task sync across time zone enabled positive') $task.Triggers[0].StartBoundary | Should -Be $expectedStartTime } } Context 'When a scheduled task is created and synchronize across time zone is enabled negative' { + BeforeDiscovery { + $configuredStartTime = '2018-10-01T01:00:00-08:00' + $expectedStartTime = (Get-Date -Date $configuredStartTime).ToUniversalTime().ToString((Get-Culture).DateTimeFormat.SortableDateTimePattern + 'zzz') + } + BeforeAll { $currentConfig = 'ScheduledTaskOnceSynchronizeAcrossTimeZoneEnabledNegative' $configDir = (Join-Path -Path $TestDrive -ChildPath $currentConfig) @@ -405,6 +431,12 @@ Describe "$($script:dscResourceName)_Integration" { $configuredStartTime = '2018-10-01T01:00:00-08:00' $expectedStartTime = (Get-Date -Date $configuredStartTime).ToUniversalTime().ToString((Get-Culture).DateTimeFormat.SortableDateTimePattern + 'zzz') + + InModuleScope -Parameters @{ + expectedStartTime = $expectedStartTime + } -ScriptBlock { + $script:expectedStartTime = $expectedStartTime + } } AfterAll { @@ -445,13 +477,18 @@ Describe "$($script:dscResourceName)_Integration" { $current.Enable | Should -BeTrue } - It 'Should have the trigger startBoundary set to ''2018-10-01T01:00:00-08:00''' { + It "Should have the trigger startBoundary set to '$expectedStartTime'" { $task = (Get-ScheduledTask -TaskName 'Test task sync across time zone enabled negative') $task.Triggers[0].StartBoundary | Should -Be $expectedStartTime } } Context 'When a scheduled task is created and synchronize across time zone is enabled zulu' { + BeforeDiscovery { + $configuredStartTime = '2018-10-01T01:00:00Z' + $expectedStartTime = (Get-Date -Date $configuredStartTime).ToUniversalTime().ToString((Get-Culture).DateTimeFormat.SortableDateTimePattern + 'zzz') + } + BeforeAll { $currentConfig = 'ScheduledTaskOnceSynchronizeAcrossTimeZoneEnabledZulu' $configDir = (Join-Path -Path $TestDrive -ChildPath $currentConfig) @@ -459,6 +496,12 @@ Describe "$($script:dscResourceName)_Integration" { $configuredStartTime = '2018-10-01T01:00:00Z' $expectedStartTime = (Get-Date -Date $configuredStartTime).ToUniversalTime().ToString((Get-Culture).DateTimeFormat.SortableDateTimePattern + 'zzz') + + InModuleScope -Parameters @{ + expectedStartTime = $expectedStartTime + } -ScriptBlock { + $script:expectedStartTime = $expectedStartTime + } } AfterAll { @@ -499,7 +542,7 @@ Describe "$($script:dscResourceName)_Integration" { $current.Enable | Should -BeTrue } - It 'Should have the trigger startBoundary set to ''2018-10-01T01:00:00+00:00''' { + It "Should have the trigger startBoundary set to '$expectedStartTime'" { $task = (Get-ScheduledTask -TaskName 'Test task sync across time zone enabled zulu') $task.Triggers[0].StartBoundary | Should -Be $expectedStartTime } diff --git a/tests/Unit/DSC_ScheduledTask.Tests.ps1 b/tests/Unit/DSC_ScheduledTask.Tests.ps1 index 583ead7d..923fe734 100644 --- a/tests/Unit/DSC_ScheduledTask.Tests.ps1 +++ b/tests/Unit/DSC_ScheduledTask.Tests.ps1 @@ -2559,6 +2559,10 @@ Describe 'DSC_ScheduledTask' { } Context 'When a scheduled task is created and synchronize across time zone is disabled' { + BeforeDiscovery { + $startTimeString = '2018-10-01T01:00:00' + } + BeforeAll { $startTimeString = '2018-10-01T01:00:00' $testParameters = $getTargetResourceParameters + @{ @@ -2570,6 +2574,12 @@ Describe 'DSC_ScheduledTask' { $startTimeStringWithOffset = '2018-10-01T01:00:00-08:00' + InModuleScope -Parameters @{ + startTimeString = $startTimeString + } -ScriptBlock { + $script:startTimeString = $startTimeString + } + Mock -CommandName Get-ScheduledTask -MockWith { @{ TaskName = $testParameters.TaskName @@ -2649,7 +2659,7 @@ Describe 'DSC_ScheduledTask' { } - It "Should set task trigger StartBoundary to $startTimeString" { + It "Should set task trigger StartBoundary to '$startTimeString'" { InModuleScope -ScriptBlock { Set-StrictMode -Version 1.0 @@ -2764,7 +2774,7 @@ Describe 'DSC_ScheduledTask' { } } - It "Should set task trigger StartBoundary to $expectedStartTimeStringWithOffset" { + It "Should set task trigger StartBoundary to '$expectedStartTimeStringWithOffset'" { InModuleScope -ScriptBlock { Set-StrictMode -Version 1.0 From 1d02de36bb5734796bb229fc26b91edac38027ed Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Fri, 29 Nov 2024 14:40:12 +0000 Subject: [PATCH 23/23] Fix integration test --- .../DSC_ScheduledTask.Integration.Tests.ps1 | 51 ++----------------- 1 file changed, 4 insertions(+), 47 deletions(-) diff --git a/tests/Integration/DSC_ScheduledTask.Integration.Tests.ps1 b/tests/Integration/DSC_ScheduledTask.Integration.Tests.ps1 index f2c353b3..e4ce2205 100644 --- a/tests/Integration/DSC_ScheduledTask.Integration.Tests.ps1 +++ b/tests/Integration/DSC_ScheduledTask.Integration.Tests.ps1 @@ -291,22 +291,12 @@ Describe "$($script:dscResourceName)_Integration" { } Context 'When a scheduled task is created and synchronize across time zone is disabled' { - BeforeDiscovery { - $expectedStartTime = '2018-10-01T01:00:00' - } - BeforeAll { $currentConfig = 'ScheduledTaskOnceSynchronizeAcrossTimeZoneDisabled' $configDir = (Join-Path -Path $TestDrive -ChildPath $currentConfig) $configMof = (Join-Path -Path $configDir -ChildPath 'localhost.mof') $expectedStartTime = '2018-10-01T01:00:00' - - InModuleScope -Parameters @{ - expectedStartTime = $expectedStartTime - } -ScriptBlock { - $script:expectedStartTime = $expectedStartTime - } } AfterAll { @@ -347,18 +337,13 @@ Describe "$($script:dscResourceName)_Integration" { $current.Enable | Should -BeTrue } - It "Should have the trigger startBoundary set to '$expectedStartTime'" { + It 'Should have the trigger startBoundary set to ''2018-10-01T01:00:00''' { $task = (Get-ScheduledTask -TaskName 'Test task sync across time zone disabled') $task.Triggers[0].StartBoundary | Should -Be $expectedStartTime } } Context 'When a scheduled task is created and synchronize across time zone is enabled positive' { - BeforeDiscovery { - $configuredStartTime = '2018-10-01T01:00:00+08:00' - $expectedStartTime = (Get-Date -Date $configuredStartTime).ToUniversalTime().ToString((Get-Culture).DateTimeFormat.SortableDateTimePattern + 'zzz') - } - BeforeAll { $currentConfig = 'ScheduledTaskOnceSynchronizeAcrossTimeZoneEnabledPositive' $configDir = (Join-Path -Path $TestDrive -ChildPath $currentConfig) @@ -366,12 +351,6 @@ Describe "$($script:dscResourceName)_Integration" { $configuredStartTime = '2018-10-01T01:00:00+08:00' $expectedStartTime = (Get-Date -Date $configuredStartTime).ToUniversalTime().ToString((Get-Culture).DateTimeFormat.SortableDateTimePattern + 'zzz') - - InModuleScope -Parameters @{ - expectedStartTime = $expectedStartTime - } -ScriptBlock { - $script:expectedStartTime = $expectedStartTime - } } AfterAll { @@ -412,18 +391,13 @@ Describe "$($script:dscResourceName)_Integration" { $current.Enable | Should -BeTrue } - It "Should have the trigger startBoundary set to '$expectedStartTime'" { + It 'Should have the trigger startBoundary set to ''2018-09-30T17:00:00+00:00''' { $task = (Get-ScheduledTask -TaskName 'Test task sync across time zone enabled positive') $task.Triggers[0].StartBoundary | Should -Be $expectedStartTime } } Context 'When a scheduled task is created and synchronize across time zone is enabled negative' { - BeforeDiscovery { - $configuredStartTime = '2018-10-01T01:00:00-08:00' - $expectedStartTime = (Get-Date -Date $configuredStartTime).ToUniversalTime().ToString((Get-Culture).DateTimeFormat.SortableDateTimePattern + 'zzz') - } - BeforeAll { $currentConfig = 'ScheduledTaskOnceSynchronizeAcrossTimeZoneEnabledNegative' $configDir = (Join-Path -Path $TestDrive -ChildPath $currentConfig) @@ -431,12 +405,6 @@ Describe "$($script:dscResourceName)_Integration" { $configuredStartTime = '2018-10-01T01:00:00-08:00' $expectedStartTime = (Get-Date -Date $configuredStartTime).ToUniversalTime().ToString((Get-Culture).DateTimeFormat.SortableDateTimePattern + 'zzz') - - InModuleScope -Parameters @{ - expectedStartTime = $expectedStartTime - } -ScriptBlock { - $script:expectedStartTime = $expectedStartTime - } } AfterAll { @@ -477,18 +445,13 @@ Describe "$($script:dscResourceName)_Integration" { $current.Enable | Should -BeTrue } - It "Should have the trigger startBoundary set to '$expectedStartTime'" { + It 'Should have the trigger startBoundary set to ''2018-10-01T09:00:00+00:00''' { $task = (Get-ScheduledTask -TaskName 'Test task sync across time zone enabled negative') $task.Triggers[0].StartBoundary | Should -Be $expectedStartTime } } Context 'When a scheduled task is created and synchronize across time zone is enabled zulu' { - BeforeDiscovery { - $configuredStartTime = '2018-10-01T01:00:00Z' - $expectedStartTime = (Get-Date -Date $configuredStartTime).ToUniversalTime().ToString((Get-Culture).DateTimeFormat.SortableDateTimePattern + 'zzz') - } - BeforeAll { $currentConfig = 'ScheduledTaskOnceSynchronizeAcrossTimeZoneEnabledZulu' $configDir = (Join-Path -Path $TestDrive -ChildPath $currentConfig) @@ -496,12 +459,6 @@ Describe "$($script:dscResourceName)_Integration" { $configuredStartTime = '2018-10-01T01:00:00Z' $expectedStartTime = (Get-Date -Date $configuredStartTime).ToUniversalTime().ToString((Get-Culture).DateTimeFormat.SortableDateTimePattern + 'zzz') - - InModuleScope -Parameters @{ - expectedStartTime = $expectedStartTime - } -ScriptBlock { - $script:expectedStartTime = $expectedStartTime - } } AfterAll { @@ -542,7 +499,7 @@ Describe "$($script:dscResourceName)_Integration" { $current.Enable | Should -BeTrue } - It "Should have the trigger startBoundary set to '$expectedStartTime'" { + It 'Should have the trigger startBoundary set to ''2018-10-01T01:00:00+00:00''' { $task = (Get-ScheduledTask -TaskName 'Test task sync across time zone enabled zulu') $task.Triggers[0].StartBoundary | Should -Be $expectedStartTime }