Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ScheduledTask: Added BuiltInUser (Issue #130) & Fixed IdleWaitTimeout… #192

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@
## Unreleased

- ScheduledTask:
- IdleWaitTimeout returned from Get-TargetResource always null - Fixes [Issue #186](https://github.com/PowerShell/ComputerManagementDsc/issues/186).
- Added BuiltInAccount Property to allow running task as one of the build in
service accounts - Fixes [Issue #130](https://github.com/PowerShell/ComputerManagementDsc/issues/130).
- Added support for Group Managed Service Accounts, implemented using the ExecuteAsGMSA
parameter. Fixes [Issue #111](https://github.com/PowerShell/ComputerManagementDsc/issues/111)
- Added support to set the Synchronize Across Time Zone option. Fixes [Issue #109](https://github.com/PowerShell/ComputerManagementDsc/issues/109)
- Added .VSCode settings for applying DSC PSSA rules - fixes [Issue #189](https://github.com/PowerShell/ComputerManagementDsc/issues/189).
- Added .VSCode settings for applying DSC PSSA rules - fixes [Issue #189](https://github.com/PowerShell/ComputerManagementDsc/issues/189).

## 5.2.0.0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ $script:localizedData = Get-LocalizedData `
True if the task should be enabled, false if it should be disabled.
Not used in Get-TargetResource.

.PARAMETER BuiltInAccount
Run the task as one of the built in service accounts.
When set ExecuteAsCredential will be ignored and LogonType will be set to 'ServiceAccount'

.PARAMETER ExecuteAsCredential
The credential this task should execute as. If not specified defaults to running
as the local system account. Cannot be used in combination with ExecuteAsGMSA.
Expand Down Expand Up @@ -277,6 +281,10 @@ function Get-TargetResource
[System.Boolean]
$Enable = $true,

[ValidateSet('SYSTEM', 'LOCAL SERVICE', 'NETWORK SERVICE')]
[System.String]
$BuiltInAccount,

[Parameter()]
[System.Management.Automation.PSCredential]
$ExecuteAsCredential,
Expand Down Expand Up @@ -511,7 +519,7 @@ function Get-TargetResource
$returnSynchronizeAcrossTimeZone = $false
}

return @{
$result = @{
TaskName = $task.TaskName
TaskPath = $task.TaskPath
StartTime = $startAt
Expand All @@ -538,7 +546,7 @@ function Get-TargetResource
AllowStartIfOnBatteries = -not $settings.DisallowStartIfOnBatteries
Hidden = $settings.Hidden
RunOnlyIfIdle = $settings.RunOnlyIfIdle
IdleWaitTimeout = ConvertTo-TimeSpanStringFromScheduledTaskString -TimeSpan $settings.IdleSettings.IdleWaitTimeout
IdleWaitTimeout = ConvertTo-TimeSpanStringFromScheduledTaskString -TimeSpan $settings.IdleSettings.WaitTimeout
NetworkName = $settings.NetworkSettings.Name
DisallowStartOnRemoteAppSession = $settings.DisallowStartOnRemoteAppSession
StartWhenAvailable = $settings.StartWhenAvailable
Expand All @@ -558,6 +566,13 @@ function Get-TargetResource
EventSubscription = $trigger.Subscription
Delay = ConvertTo-TimeSpanStringFromScheduledTaskString -TimeSpan $trigger.Delay
}

if (($result.ContainsKey('LogonType')) -and ($result['LogonType'] -ieq 'ServiceAccount'))
{
$result.Add('BuiltInAccount', $task.Principal.UserId)
}

return $result
}
}

Expand Down Expand Up @@ -604,6 +619,10 @@ function Get-TargetResource
.PARAMETER Enable
True if the task should be enabled, false if it should be disabled.

.PARAMETER BuiltInAccount
Run the task as one of the built in service accounts.
When set ExecuteAsCredential will be ignored and LogonType will be set to 'ServiceAccount'

.PARAMETER ExecuteAsCredential
The credential this task should execute as. If not specified defaults to running
as the local system account. Cannot be used in combination with ExecuteAsGMSA.
Expand Down Expand Up @@ -786,6 +805,10 @@ function Set-TargetResource
[System.Boolean]
$Enable = $true,

[ValidateSet('SYSTEM', 'LOCAL SERVICE', 'NETWORK SERVICE')]
[System.String]
$BuiltInAccount,

[Parameter()]
[System.Management.Automation.PSCredential]
$ExecuteAsCredential,
Expand Down Expand Up @@ -945,9 +968,9 @@ function Set-TargetResource
and the action executable isn't specified then disable the task
#>
if ($currentValues.Ensure -eq 'Present' `
-and $currentValues.Enable `
-and -not $Enable `
-and -not $PSBoundParameters.ContainsKey('ActionExecutable'))
-and $currentValues.Enable `
-and -not $Enable `
-and -not $PSBoundParameters.ContainsKey('ActionExecutable'))
{
Write-Verbose -Message ($script:localizedData.DisablingExistingScheduledTask -f $TaskName, $TaskPath)
Disable-ScheduledTask -TaskName $TaskName -TaskPath $TaskPath
Expand Down Expand Up @@ -990,14 +1013,15 @@ function Set-TargetResource
-ArgumentName EventSubscription
}

if ($ExecuteAsCredential -and $ExecuteAsGMSA)
if ($ExecuteAsGMSA -and ($ExecuteAsCredential -or $BuiltInAccount))
{
New-InvalidArgumentException `
-Message ($script:localizedData.gMSAandCredentialError) `
-ArgumentName ExecuteAsGMSA
}

if($SynchronizeAcrossTimeZone -and ($ScheduleType -notin @('Once', 'Daily', 'Weekly'))) {
if ($SynchronizeAcrossTimeZone -and ($ScheduleType -notin @('Once', 'Daily', 'Weekly')))
{
New-InvalidArgumentException `
-Message ($script:localizedData.SynchronizeAcrossTimeZoneInvalidScheduleType) `
-ArgumentName SynchronizeAcrossTimeZone
Expand Down Expand Up @@ -1245,7 +1269,18 @@ function Set-TargetResource
# Prepare the register arguments
$registerArguments = @{}

if ($PSBoundParameters.ContainsKey('ExecuteAsGMSA'))
$username = $null
if ($PSBoundParameters.ContainsKey('BuiltInAccount'))
{
<#
The validateset on BuiltInAccount has already checked the non-null
value to be 'LOCAL SERVICE', 'NETWORK SERVICE' or 'SYSTEM'
#>
$username = 'NT AUTHORITY\' + $BuiltInAccount
$registerArguments.Add('User', $username)
$LogonType = 'ServiceAccount'
}
elseif ($PSBoundParameters.ContainsKey('ExecuteAsGMSA'))
{
$username = $ExecuteAsGMSA
$LogonType = 'Password'
Expand All @@ -1269,6 +1304,11 @@ function Set-TargetResource
}
else
{
<#
'NT AUTHORITY\SYSTEM' basically gives the schedule task admin
privileges, should we default to 'NT AUTHORITY\LOCAL SERVICE'
instead?
#>
$username = 'NT AUTHORITY\SYSTEM'
$registerArguments.Add('User', $username)
$LogonType = 'ServiceAccount'
Expand Down Expand Up @@ -1331,7 +1371,7 @@ function Set-TargetResource
$scheduledTask.Description = $Description
}

if($scheduledTask.Triggers[0].StartBoundary)
if ($scheduledTask.Triggers[0].StartBoundary)
{
<#
The way New-ScheduledTaskTrigger writes the StartBoundary has issues because it does not take
Expand Down Expand Up @@ -1367,8 +1407,8 @@ function Set-TargetResource

# Register the scheduled task

$registerArguments.Add('TaskName',$TaskName)
$registerArguments.Add('TaskPath',$TaskPath)
$registerArguments.Add('TaskName', $TaskName)
$registerArguments.Add('TaskPath', $TaskPath)
$registerArguments.Add('InputObject', $scheduledTask)

$null = Register-ScheduledTask @registerArguments
Expand Down Expand Up @@ -1426,6 +1466,10 @@ function Set-TargetResource
.PARAMETER Enable
True if the task should be enabled, false if it should be disabled.

.PARAMETER BuiltInAccount
Run the task as one of the built in service accounts.
When set ExecuteAsCredential will be ignored and LogonType will be set to 'ServiceAccount'

.PARAMETER ExecuteAsCredential
The credential this task should execute as. If not specified defaults to running
as the local system account. Cannot be used in combination with ExecuteAsGMSA.
Expand Down Expand Up @@ -1609,6 +1653,10 @@ function Test-TargetResource
[System.Boolean]
$Enable = $true,

[ValidateSet('SYSTEM', 'LOCAL SERVICE', 'NETWORK SERVICE')]
[System.String]
$BuiltInAccount,

[Parameter()]
[System.Management.Automation.PSCredential]
$ExecuteAsCredential,
Expand Down Expand Up @@ -1824,12 +1872,38 @@ function Test-TargetResource
return $false
}

if ($PSBoundParameters.ContainsKey('ExecuteAsCredential'))
if ($PSBoundParameters.ContainsKey('BuiltInAccount'))
{

$PSBoundParameters.User = $BuiltInAccount
$currentValues.User = $BuiltInAccount

$PSBoundParameters['LogonType'] = 'ServiceAccount'
$currentValues['LogonType'] = 'ServiceAccount'
}
elseif ($PSBoundParameters.ContainsKey('ExecuteAsCredential'))
{
# The password of the execution credential can not be compared
$username = $ExecuteAsCredential.UserName
$PSBoundParameters['ExecuteAsCredential'] = $username
}
else
{
# Must be running as System, login type is ServiceAccount
$PSBoundParameters['LogonType'] = 'ServiceAccount'
$currentValues['LogonType'] = 'ServiceAccount'
}

if ($PSBoundParameters.ContainsKey('WeeksInterval') -and ((-not $currentValues.ContainsKey('WeeksInterval')) -or ($null -eq $currentValues['WeeksInterval'])))
{
<#
The WeeksInterval parameter is defaulted to 1, even when the property
is unset/undefined for the current task returned from Get-TargetResouce
initialise a missing or null WeeksInterval to spurious calls to
Set-TargetResouce
#>
$currentValues.WeeksInterval = $PSBoundParameters['WeeksInterval']
}

if ($PSBoundParameters.ContainsKey('ExecuteAsGMSA'))
{
Expand All @@ -1848,6 +1922,14 @@ function Test-TargetResource

$desiredValues = $PSBoundParameters
$desiredValues.TaskPath = $TaskPath
if ($desiredValues.ContainsKey('Verbose'))
{
<#
Initialise a missing or null Verbose to avoid spurious
calls to Set-TargetResouce
#>
$currentValues.Add('Verbose', $desiredValues['Verbose'])
}

Write-Verbose -Message ($script:localizedData.TestingDscParameterStateMessage)

Expand Down Expand Up @@ -2036,7 +2118,7 @@ Function Get-DateTimeString

$format = (Get-Culture).DateTimeFormat.SortableDateTimePattern

if($SynchronizeAcrossTimeZone)
if ($SynchronizeAcrossTimeZone)
{
$returnDate = (Get-Date -Date $Date -Format $format) + (Get-Date -Format 'zzz')
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,31 @@
[ClassVersion("1.0.0.0"), FriendlyName("ScheduledTask")]
class MSFT_ScheduledTask : OMI_BaseResource
{
[Key, Description("The name of the task")] string TaskName;
[Write, Description("The path to the task - defaults to the root directory")] string TaskPath;
[Write, Description("The task description")] string Description;
[Write, Description("The path to the .exe for this task")] string ActionExecutable;
[Write, Description("The arguments to pass the executable")] string ActionArguments;
[Write, Description("The working path to specify for the executable")] string ActionWorkingPath;
[Write, Description("When should the task be executed"), ValueMap{"Once", "Daily", "Weekly", "AtStartup", "AtLogOn", "OnEvent"}, Values{"Once", "Daily", "Weekly", "AtStartup", "AtLogOn", "OnEvent"}] string ScheduleType;
[Key, Description("The name of the task.")] string TaskName;
[Write, Description("The path to the task - defaults to the root directory.")] string TaskPath;
[Write, Description("The task description.")] string Description;
[Write, Description("The path to the .exe for this task.")] string ActionExecutable;
[Write, Description("The arguments to pass the executable.")] string ActionArguments;
[Write, Description("The working path to specify for the executable.")] string ActionWorkingPath;
[Write, Description("When should the task be executed."), ValueMap{"Once", "Daily", "Weekly", "AtStartup", "AtLogOn", "OnEvent"}, Values{"Once", "Daily", "Weekly", "AtStartup", "AtLogOn", "OnEvent"}] string ScheduleType;
[Write, Description("How many units (minutes, hours, days) between each run of this task?")] String RepeatInterval;
[Write, Description("The time of day this task should start at - defaults to 12:00 AM. Not valid for AtLogon and AtStartup tasks")] DateTime StartTime;
[Write, Description("The time of day this task should start at - defaults to 12:00 AM. Not valid for AtLogon and AtStartup tasks.")] DateTime StartTime;
[Write, Description("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;
[Write, Description("The credential this task should execute as. If not specified defaults to running as the local system account"), EmbeddedInstance("MSFT_Credential")] string ExecuteAsCredential;
[Write, Description("The gMSA (Group Managed Service Account) this task should execute as. Cannot be used in combination with ExecuteAsCredential.")] string ExecuteAsGMSA;
[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;
[Write, Description("Run the task as one of the built in service accounts. When set ExecuteAsCredential will be ignored and LogonType will be set to 'ServiceAccount'."), ValueMap{"SYSTEM", "LOCAL SERVICE", "NETWORK SERVICE"}, Values{"SYSTEM", "LOCAL SERVICE", "NETWORK SERVICE"}] string BuiltInAccount;
[Write, Description("The credential this task should execute as. If not specified defaults to running as the local system account."), EmbeddedInstance("MSFT_Credential")] string ExecuteAsCredential;
[Write, Description("The gMSA (Group Managed Service Account) this task should execute as. Cannot be used in combination with ExecuteAsCredential or BuiltInAccount.")] string ExecuteAsGMSA;
[Write, Description("Specifies the interval between the days in the schedule. An interval of 1 produces a daily schedule. An interval of 2 produces an every-other day schedule.")] Uint32 DaysInterval;
[Write, Description("Specifies a random amount of time to delay the start time of the trigger. The delay time is a random time between the time the task triggers and the time that you specify in this setting.")] String RandomDelay;
[Write, Description("Specifies how long the repetition pattern repeats after the task starts. May be set to `Indefinitely` to specify an indefinite duration.")] String RepetitionDuration;
[Write, Description("Specifies an array of the days of the week on which Task Scheduler runs the task.")] String DaysOfWeek[];
[Write, Description("Specifies the interval between the weeks in the schedule. An interval of 1 produces a weekly schedule. An interval of 2 produces an every-other week schedule.")] Uint32 WeeksInterval;
[Write, Description("Specifies the identifier of the user for a trigger that starts a task when a user logs on.")] String User;
[Write, Description("Indicates whether the task is prohibited to run on demand or not. Defaults to $false")] Boolean DisallowDemandStart;
[Write, Description("Indicates whether the task is prohibited to be terminated or not. Defaults to $false")] Boolean DisallowHardTerminate;
[Write, Description("Indicates whether the task is prohibited to run on demand or not. Defaults to $false.")] Boolean DisallowDemandStart;
[Write, Description("Indicates whether the task is prohibited to be terminated or not. Defaults to $false.")] Boolean DisallowHardTerminate;
[Write, Description("The task compatibility level. Defaults to Vista."), ValueMap{"AT","V1","Vista","Win7","Win8"}, Values{"AT","V1","Vista","Win7","Win8"}] String Compatibility;
[Write, Description("Indicates whether the task should start if the machine is on batteries or not. Defaults to $false")] Boolean AllowStartIfOnBatteries;
[Write, Description("Indicates whether the task should start if the machine is on batteries or not. Defaults to $false.")] Boolean AllowStartIfOnBatteries;
[Write, Description("Indicates that the task is hidden in the Task Scheduler UI.")] Boolean Hidden;
[Write, Description("Indicates that Task Scheduler runs the task only when the computer is idle.")] Boolean RunOnlyIfIdle;
[Write, Description("Specifies the amount of time that Task Scheduler waits for an idle condition to occur.")] String IdleWaitTimeout;
Expand All @@ -44,6 +45,6 @@ class MSFT_ScheduledTask : OMI_BaseResource
[Write, Description("Indicates that Task Scheduler runs the task only when a network is available. Task Scheduler uses the NetworkID parameter and NetworkName parameter that you specify in this cmdlet to determine if the network is available.")] Boolean RunOnlyIfNetworkAvailable;
[Write, Description("Specifies the level of user rights that Task Scheduler uses to run the tasks that are associated with the principal. Defaults to 'Limited'."), ValueMap{"Limited","Highest"}, Values{"Limited","Highest"}] String RunLevel;
[Write, Description("Specifies the security logon method that Task Scheduler uses to run the tasks that are associated with the principal."), ValueMap{"Group","Interactive","InteractiveOrPassword","None","Password","S4U","ServiceAccount"}, Values{"Group","Interactive","InteractiveOrPassword","None","Password","S4U","ServiceAccount"}] String LogonType;
[Write, Description("Specifies the EventSubscription in XML. This can be easily generated using the Windows Eventlog Viewer. For the query schema please check: https://docs.microsoft.com/en-us/windows/desktop/WES/queryschema-schema. Can only be used in combination with ScheduleType OnEvent")] String EventSubscription;
[Write, Description("Specifies a delay to the start of the trigger. The delay is a static delay before the task is executed. Can only be used in combination with ScheduleType OnEvent")] String Delay;
[Write, Description("Specifies the EventSubscription in XML. This can be easily generated using the Windows Eventlog Viewer. For the query schema please check: https://docs.microsoft.com/en-us/windows/desktop/WES/queryschema-schema. Can only be used in combination with ScheduleType OnEvent.")] String EventSubscription;
[Write, Description("Specifies a delay to the start of the trigger. The delay is a static delay before the task is executed. Can only be used in combination with ScheduleType OnEvent.")] String Delay;
};
Loading