Skip to content

Commit c8977b0

Browse files
authored
ScheduledTask: Add Event ValueQueries support, prevent DaysOfWeek ordering causing drift (#431)
1 parent 58f77e4 commit c8977b0

File tree

9 files changed

+179
-11
lines changed

9 files changed

+179
-11
lines changed

CHANGELOG.md

+15
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
55

66
## [Unreleased]
77

8+
### Added
9+
10+
- ScheduledTask
11+
- Added support for configuring Event ValueQueries, allowing the triggering event to be
12+
parsed for values which are sent to the scheduled task script.
13+
Fixes [Issue #392](https://github.com/dsccommunity/ComputerManagementDsc/issues/392).
14+
15+
### Fixed
16+
17+
- ScheduledTask
18+
- Resolved an issue where DaysOfWeek array ordering can cause configuration drift.
19+
Fixes [Issue #354](https://github.com/dsccommunity/ComputerManagementDsc/issues/354).
20+
- Update build process to pin GitVersion to 5.* to resolve errors
21+
(https://github.com/gaelcolas/Sampler/issues/477).
22+
823
### Changed
924

1025
- CI Pipeline

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ The **ComputerManagementDsc** module contains the following resources:
5858
settings on the local machine.
5959
- **SmbShare**: This resource is used to manage SMB shares on a machine.
6060
- **SystemLocale**: This resource is used to set the system locale on a
61-
Windows machine
61+
Windows machine.
6262
- **TimeZone**: This resource is used for setting the time zone on a machine.
6363
- **UserAccountControl**: This resource allows you to configure the notification
6464
level or granularly configure the User Account Control for the computer.

appveyor.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ build_script:
4242
if (-not $env:APPVEYOR_PULL_REQUEST_NUMBER) { Write-Host -ForegroundColor 'Yellow' -Object 'Not a pull request, skipping.'; return }
4343
4444
# Set module version using GitVersion
45-
dotnet tool install --global GitVersion.Tool
45+
dotnet tool install --global GitVersion.Tool --version 5.*
4646
$env:IGNORE_NORMALISATION_GIT_HEAD_MOVE = 1
4747
dotnet-gitversion
4848
$gitVersionObject = dotnet-gitversion | ConvertFrom-Json

azure-pipelines.yml

+1-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ stages:
2727
vmImage: 'windows-latest'
2828
steps:
2929
- pwsh: |
30-
dotnet tool install --global GitVersion.Tool
30+
dotnet tool install --global GitVersion.Tool --version 5.*
3131
$gitVersionObject = dotnet-gitversion | ConvertFrom-Json
3232
$gitVersionObject.PSObject.Properties.ForEach{
3333
Write-Host -Object "Setting Task Variable '$($_.Name)' with value '$($_.Value)'."
@@ -309,4 +309,3 @@ stages:
309309
GitHubToken: $(GitHubToken)
310310
ReleaseBranch: main
311311
MainGitBranch: main
312-

source/DSCResources/DSC_ScheduledTask/DSC_ScheduledTask.psm1

+92-3
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,12 @@ function Get-TargetResource
228228
valid in combination with the OnEvent Schedule Type. For the query schema please check:
229229
https://docs.microsoft.com/en-us/windows/desktop/WES/queryschema-schema
230230
231+
.PARAMETER EventValueQueries
232+
Specifies event value queries. This parameter is only valid in combination with the OnEvent
233+
Schedule Type. Receives a hashtable where the key is a property value for an event and
234+
the value is an XPath event query. For more detailed syntax check:
235+
https://learn.microsoft.com/en-us/windows/win32/taskschd/eventtrigger-valuequeries.
236+
231237
.PARAMETER Delay
232238
The time to wait after an event based trigger was triggered. This parameter is only
233239
valid in combination with the OnEvent Schedule Type.
@@ -424,6 +430,10 @@ function Set-TargetResource
424430
[System.String]
425431
$EventSubscription,
426432

433+
[Parameter()]
434+
[Microsoft.Management.Infrastructure.CimInstance[]]
435+
$EventValueQueries,
436+
427437
[Parameter()]
428438
[System.String]
429439
$Delay = '00:00:00'
@@ -689,6 +699,7 @@ function Set-TargetResource
689699
$trigger = New-CimInstance -CimClass $cimTriggerClass -ClientOnly
690700
$trigger.Enabled = $true
691701
$trigger.Subscription = $EventSubscription
702+
$trigger.ValueQueries = ConvertTo-TaskNamedValuePairCollectionFromKeyValuePairArray -Array $EventValueQueries
692703
}
693704
}
694705

@@ -1120,6 +1131,12 @@ function Set-TargetResource
11201131
valid in combination with the OnEvent Schedule Type. For the query schema please check:
11211132
https://docs.microsoft.com/en-us/windows/desktop/WES/queryschema-schema
11221133
1134+
.PARAMETER EventValueQueries
1135+
Specifies event value queries. This parameter is only valid in combination with the OnEvent
1136+
Schedule Type. Receives a hashtable where the key is a property value for an event and
1137+
the value is an XPath event query. For more detailed syntax check:
1138+
https://learn.microsoft.com/en-us/windows/win32/taskschd/eventtrigger-valuequeries.
1139+
11231140
.PARAMETER Delay
11241141
The time to wait after an event based trigger was triggered. This parameter is only
11251142
valid in combination with the OnEvent Schedule Type.
@@ -1317,6 +1334,10 @@ function Test-TargetResource
13171334
[System.String]
13181335
$EventSubscription,
13191336

1337+
[Parameter()]
1338+
[Microsoft.Management.Infrastructure.CimInstance[]]
1339+
$EventValueQueries,
1340+
13201341
[Parameter()]
13211342
[System.String]
13221343
$Delay = '00:00:00'
@@ -1486,8 +1507,8 @@ function Test-TargetResource
14861507
The WeeksInterval parameter of this function defaults to 1,
14871508
even though the value of the WeeksInterval property maybe
14881509
unset/undefined in the object $currentValues returned from
1489-
Get-TargetResouce. To avoid Test-TargetResouce returning false
1490-
and generating spurious calls to Set-TargetResouce, default
1510+
Get-TargetResource. To avoid Test-TargetResource returning false
1511+
and generating spurious calls to Set-TargetResource, default
14911512
an undefined $currentValues.WeeksInterval to the value of
14921513
$WeeksInterval.
14931514
#>
@@ -1525,7 +1546,7 @@ function Test-TargetResource
15251546
{
15261547
<#
15271548
Initialise a missing or null Verbose to avoid spurious
1528-
calls to Set-TargetResouce
1549+
calls to Set-TargetResource
15291550
#>
15301551
$currentValues.Add('Verbose', $desiredValues['Verbose'])
15311552
}
@@ -1535,6 +1556,7 @@ function Test-TargetResource
15351556
return Test-DscParameterState `
15361557
-CurrentValues $currentValues `
15371558
-DesiredValues $desiredValues `
1559+
-SortArrayValues `
15381560
-Verbose:$VerbosePreference
15391561
}
15401562

@@ -1922,6 +1944,7 @@ function Get-CurrentResource
19221944
RunLevel = [System.String] $task.Principal.RunLevel
19231945
LogonType = [System.String] $task.Principal.LogonType
19241946
EventSubscription = $trigger.Subscription
1947+
EventValueQueries = ConvertTo-HashtableFromTaskNamedValuePairCollection -Array $trigger.ValueQueries
19251948
Delay = ConvertTo-TimeSpanStringFromScheduledTaskString -TimeSpan $trigger.Delay
19261949
}
19271950

@@ -1943,6 +1966,72 @@ function Get-CurrentResource
19431966
return $result
19441967
}
19451968

1969+
<#
1970+
.SYNOPSIS
1971+
Converts CimInstance array of type MSFT_TaskNamedValue to hashtable
1972+
1973+
.PARAMETER Array
1974+
The array of MSFT_TaskNamedValue to convert to a hashtable.
1975+
#>
1976+
function ConvertTo-HashtableFromTaskNamedValuePairCollection
1977+
{
1978+
[CmdletBinding()]
1979+
[OutputType([System.Collections.Hashtable])]
1980+
param
1981+
(
1982+
[Parameter()]
1983+
[Microsoft.Management.Infrastructure.CimInstance[]]
1984+
$Array
1985+
)
1986+
1987+
$hashtable = @{}
1988+
1989+
foreach ($item in $Array)
1990+
{
1991+
$hashtable += @{
1992+
$item.Name = $item.Value
1993+
}
1994+
}
1995+
1996+
return $hashtable
1997+
}
1998+
1999+
<#
2000+
.SYNOPSIS
2001+
Converts CimInstance array of type MSFT_KeyValuePair to array of type MSFT_TaskNamedValue
2002+
2003+
.PARAMETER Array
2004+
The array of MSFT_KeyValuePair to convert to an array of type MSFT_TaskNamedValue.
2005+
#>
2006+
function ConvertTo-TaskNamedValuePairCollectionFromKeyValuePairArray
2007+
{
2008+
[CmdletBinding()]
2009+
[OutputType([Microsoft.Management.Infrastructure.CimInstance[]])]
2010+
param
2011+
(
2012+
[Parameter()]
2013+
[Microsoft.Management.Infrastructure.CimInstance[]]
2014+
$Array
2015+
)
2016+
2017+
$cimNamedValueClass = Get-CimClass -ClassName MSFT_TaskNamedValue -Namespace Root/Microsoft/Windows/TaskScheduler:MSFT_TaskNamedValue
2018+
2019+
$namedValueArray = [Microsoft.Management.Infrastructure.CimInstance[]]@()
2020+
2021+
foreach ($item in $Array)
2022+
{
2023+
$namedValue = New-CimInstance -CimClass $cimNamedValueClass `
2024+
-Property @{
2025+
Name = $item.key
2026+
Value = $item.Value
2027+
} `
2028+
-ClientOnly
2029+
$namedValueArray += $namedValue
2030+
}
2031+
2032+
return $namedValueArray
2033+
}
2034+
19462035
<#
19472036
.SYNOPSIS
19482037
Test if a date string contains a time zone.

source/DSCResources/DSC_ScheduledTask/DSC_ScheduledTask.schema.mof

+1
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,6 @@ class DSC_ScheduledTask : OMI_BaseResource
4646
[Write, Description("Specifies the level of user rights that Task Scheduler uses to run the tasks that are associated with the principal. Defaults to 'Limited'."), ValueMap{"Limited","Highest"}, Values{"Limited","Highest"}] String RunLevel;
4747
[Write, Description("Specifies the security logon method that Task Scheduler uses to run the tasks that are associated with the principal."), ValueMap{"Group","Interactive","InteractiveOrPassword","None","Password","S4U","ServiceAccount"}, Values{"Group","Interactive","InteractiveOrPassword","None","Password","S4U","ServiceAccount"}] String LogonType;
4848
[Write, Description("Specifies the EventSubscription in XML. This can be easily generated using the Windows Eventlog Viewer. For the query schema please check: https://docs.microsoft.com/en-us/windows/desktop/WES/queryschema-schema. Can only be used in combination with ScheduleType OnEvent.")] String EventSubscription;
49+
[Write, Description("Specifies the EventValueQueries. Receives a hashtable where the key is a property value for an event and the value is an XPath event query. For more detailed syntax check: https://learn.microsoft.com/en-us/windows/win32/taskschd/eventtrigger-valuequeries."), EmbeddedInstance("MSFT_KeyValuePair")] String EventValueQueries[];
4950
[Write, Description("Specifies a delay to the start of the trigger. The delay is a static delay before the task is executed. Can only be used in combination with ScheduleType OnEvent.")] String Delay;
5051
};

source/Examples/Resources/ScheduledTask/13-ScheduledTask_CreateScheduledTasksOnEvent_Config.ps1

+6-1
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,13 @@ Configuration ScheduledTask_CreateScheduledTasksOnEvent_Config
3737
Ensure = 'Present'
3838
ScheduleType = 'OnEvent'
3939
ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe'
40-
ActionArguments = '-Command Set-Content -Path c:\temp\seeme.txt -Value ''Worked!'''
40+
ActionArguments = '-Command Set-Content -Path c:\temp\seeme.txt -Value ''$(Service) $(DependsOnService) $(ErrorCode) Worked!'''
4141
EventSubscription = '<QueryList><Query Id="0" Path="System"><Select Path="System">*[System[Provider[@Name=''Service Control Manager''] and (Level=2) and (EventID=7001)]]</Select></Query></QueryList>'
42+
EventValueQueries = @{
43+
"Service" = "Event/EventData/Data[@Name='param1']"
44+
"DependsOnService" = "Event/EventData/Data[@Name='param2']"
45+
"ErrorCode" = "Event/EventData/Data[@Name='param3']"
46+
}
4247
Delay = '00:00:30'
4348
}
4449
}

tests/Integration/DSC_ScheduledTask.config.ps1

+18-3
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,13 @@ Configuration ScheduledTaskOnEventAdd
252252
Ensure = 'Present'
253253
ScheduleType = 'OnEvent'
254254
ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe'
255-
ActionArguments = '-Command Set-Content -Path c:\temp\seeme.txt -Value ''Worked!'''
255+
ActionArguments = '-Command Set-Content -Path c:\temp\seeme.txt -Value ''$(Service) $(DependsOnService) $(ErrorCode) Worked!'''
256256
EventSubscription = '<QueryList><Query Id="0" Path="System"><Select Path="System">*[System[Provider[@Name=''Service Control Manager''] and (Level=2) and (EventID=7001)]]</Select></Query></QueryList>'
257+
EventValueQueries = @{
258+
"Service" = "Event/EventData/Data[@Name='param1']"
259+
"DependsOnService" = "Event/EventData/Data[@Name='param2']"
260+
"ErrorCode" = "Event/EventData/Data[@Name='param3']"
261+
}
257262
Delay = '00:00:30'
258263
}
259264
}
@@ -456,8 +461,13 @@ Configuration ScheduledTaskOnEventMod
456461
Ensure = 'Present'
457462
ScheduleType = 'OnEvent'
458463
ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe'
459-
ActionArguments = '-Command Set-Content -Path c:\temp\seeme.txt -Value ''Worked!'''
464+
ActionArguments = '-Command Set-Content -Path c:\temp\seeme.txt -Value ''$(Service) $(DependsOnService) $(ErrorCode) Worked!'''
460465
EventSubscription = '<QueryList><Query Id="0" Path="System"><Select Path="System">*[System[Provider[@Name=''Service Control Manager''] and (Level=2) and (EventID=7002)]]</Select></Query></QueryList>'
466+
EventValueQueries = @{
467+
"Service" = "Event/EventData/Data[@Name='param1']"
468+
"DependsOnService" = "Event/EventData/Data[@Name='param2']"
469+
"ErrorCode" = "Event/EventData/Data[@Name='param3']"
470+
}
461471
Delay = '00:00:45'
462472
}
463473
}
@@ -653,8 +663,13 @@ Configuration ScheduledTaskOnEventDel
653663
Ensure = 'Absent'
654664
ScheduleType = 'OnEvent'
655665
ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe'
656-
ActionArguments = '-Command Set-Content -Path c:\temp\seeme.txt -Value ''Worked!'''
666+
ActionArguments = '-Command Set-Content -Path c:\temp\seeme.txt -Value ''$(Service) $(DependsOnService) $(ErrorCode) Worked!'''
657667
EventSubscription = '<QueryList><Query Id="0" Path="System"><Select Path="System">*[System[Provider[@Name=''Service Control Manager''] and (Level=2) and (EventID=7001)]]</Select></Query></QueryList>'
668+
EventValueQueries = @{
669+
"Service" = "Event/EventData/Data[@Name='param1']"
670+
"DependsOnService" = "Event/EventData/Data[@Name='param2']"
671+
"ErrorCode" = "Event/EventData/Data[@Name='param3']"
672+
}
658673
Delay = '00:00:30'
659674
}
660675
}

tests/Unit/DSC_ScheduledTask.Tests.ps1

+44
Original file line numberDiff line numberDiff line change
@@ -1599,6 +1599,13 @@ try
15991599
ScheduleType = 'OnEvent'
16001600
ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe'
16011601
EventSubscription = '<QueryList><Query Id="0" Path="System"><Select Path="System">*[System[Provider[@Name=''User32''] and EventID=1600]]</Select></Query></QueryList>'
1602+
EventValueQueries = [Microsoft.Management.Infrastructure.CimInstance[]] (
1603+
ConvertTo-CimInstance -Hashtable @{
1604+
Service = "Event/EventData/Data[@Name='param1']"
1605+
DependsOnService = "Event/EventData/Data[@Name='param2']"
1606+
ErrorCode = "Event/EventData/Data[@Name='param3']"
1607+
}
1608+
)
16021609
Delay = '00:01:00'
16031610
Enable = $true
16041611
Verbose = $true
@@ -1614,6 +1621,17 @@ try
16141621
Triggers = [pscustomobject] @{
16151622
Delay = 'PT1M'
16161623
Subscription = $testParameters.EventSubscription
1624+
ValueQueries = @(
1625+
$testParameters.EventValueQueries | ForEach-Object {
1626+
New-CimInstance -ClassName MSFT_TaskNamedValue `
1627+
-Namespace Root/Microsoft/Windows/TaskScheduler:MSFT_TaskNamedValue `
1628+
-Property @{
1629+
Name = $_.Key
1630+
Value = $_.Value
1631+
} `
1632+
-ClientOnly
1633+
}
1634+
)
16171635
CimClass = @{
16181636
CimClassName = 'MSFT_TaskEventTrigger'
16191637
}
@@ -1631,6 +1649,7 @@ try
16311649
$result.Ensure | Should -Be 'Present'
16321650
$result.ScheduleType | Should -Be 'OnEvent'
16331651
$result.EventSubscription | Should -Be $testParameters.EventSubscription
1652+
Test-DscParameterState -CurrentValues $result.EventValueQueries -DesiredValues $testParameters.EventValueQueries | Should -BeTrue
16341653
$result.Delay | Should -Be $testParameters.Delay
16351654
}
16361655

@@ -1644,6 +1663,13 @@ try
16441663
ScheduleType = 'OnEvent'
16451664
ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe'
16461665
EventSubscription = '<QueryList><Query Id="0" Path="System"><Select Path="System">*[System[Provider[@Name=''User32''] and EventID=1600]]</Select></Query></QueryList>'
1666+
EventValueQueries = [Microsoft.Management.Infrastructure.CimInstance[]] (
1667+
ConvertTo-CimInstance -Hashtable @{
1668+
Service = "Event/EventData/Data[@Name='param1']"
1669+
DependsOnService = "Event/EventData/Data[@Name='param2']"
1670+
ErrorCode = "Event/EventData/Data[@Name='param3']"
1671+
}
1672+
)
16471673
Delay = '00:01:00'
16481674
Enable = $true
16491675
Verbose = $true
@@ -1671,6 +1697,13 @@ try
16711697
ScheduleType = 'OnEvent'
16721698
ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe'
16731699
EventSubscription = '<QueryList><Query Id="0" Path="System"><Select Path="System">*[System[Provider[@Name=''User32''] and EventID=1600]]</Select></Query></QueryList>'
1700+
EventValueQueries = [Microsoft.Management.Infrastructure.CimInstance[]] (
1701+
ConvertTo-CimInstance -Hashtable @{
1702+
Service = "Event/EventData/Data[@Name='param1']"
1703+
DependsOnService = "Event/EventData/Data[@Name='param2']"
1704+
ErrorCode = "Event/EventData/Data[@Name='param3']"
1705+
}
1706+
)
16741707
Delay = '00:05:00'
16751708
Enable = $true
16761709
Verbose = $true
@@ -1686,6 +1719,17 @@ try
16861719
Triggers = [pscustomobject] @{
16871720
Delay = 'PT1M'
16881721
Subscription = '<QueryList><Query Id="0" Path="System"><Select Path="System">*[System[Provider[@Name=''User32''] and EventID=1601]]</Select></Query></QueryList>'
1722+
ValueQueries = @(
1723+
$testParameters.EventValueQueries | Select-Object -SkipLast 1 | ForEach-Object {
1724+
New-CimInstance -ClassName MSFT_TaskNamedValue `
1725+
-Namespace Root/Microsoft/Windows/TaskScheduler:MSFT_TaskNamedValue `
1726+
-Property @{
1727+
Name = $_.Key
1728+
Value = $_.Value
1729+
} `
1730+
-ClientOnly
1731+
}
1732+
)
16891733
CimClass = @{
16901734
CimClassName = 'MSFT_TaskEventTrigger'
16911735
}

0 commit comments

Comments
 (0)