Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
13 changes: 10 additions & 3 deletions REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ The basic property that the resource should be in.

Default value: `present`

##### `group`

The group to run the scheduled task as.

Please also note that Puppet must be running as a privileged user
in order to manage `scheduled_task` resources. Running as an
unprivileged user will result in 'access denied' errors.

##### `trigger`

One or more triggers defining when the task should run. A single trigger is
Expand Down Expand Up @@ -205,7 +213,8 @@ conditions will fail with a reported error of 'The operation
completed successfully'. It is recommended that you either
choose another user to run the scheduled task, or alter the
security policy to allow v1 scheduled tasks to run as the
'SYSTEM' account. Defaults to 'SYSTEM'.
'SYSTEM' account.
Defaults to 'SYSTEM' unless the group property is set.

Please also note that Puppet must be running as a privileged user
in order to manage `scheduled_task` resources. Running as an
Expand All @@ -216,8 +225,6 @@ user does not end with a dollar sign (`$`) signifying a Group
Managed Service Account (gMSA), the task will be created with
`Run only when user is logged on` specified.

Default value: `system`

##### `working_dir`

The full path of the directory in which to start the command.
Expand Down
22 changes: 20 additions & 2 deletions lib/puppet/provider/scheduled_task/taskscheduler_api2.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ def user
account
end

def group
task.group_information
end

def compatibility
task.compatibility
end
Expand All @@ -79,6 +83,14 @@ def user_insync?(current, should)
Puppet::Util::Windows::SID.name_to_sid(current) == Puppet::Util::Windows::SID.name_to_sid(should[0])
end

def group_insync?(current, should)
return false unless current

# By comparing account SIDs we don't have to worry about case
# sensitivity, or canonicalization of the account name.
Puppet::Util::Windows::SID.name_to_sid(current) == Puppet::Util::Windows::SID.name_to_sid(should[0])
end

def trigger_insync?(current, should)
should = [should] unless should.is_a?(Array)
current = [current] unless current.is_a?(Array)
Expand Down Expand Up @@ -177,12 +189,18 @@ def user=(value)
end
end

def group=(value)
raise("Invalid group: #{value}") unless Puppet::Util::Windows::SID.name_to_sid(value)

task.set_group_information(value)
end

def create
@triggers = nil
@task = PuppetX::PuppetLabs::ScheduledTask::Task.new(resource[:name])
self.command = resource[:command]

[:arguments, :working_dir, :enabled, :trigger, :user, :compatibility, :description].each do |prop|
[:arguments, :working_dir, :enabled, :trigger, :user, :group, :compatibility, :description].each do |prop|
send("#{prop}=", resource[prop]) if resource[prop]
end
end
Expand All @@ -202,7 +220,7 @@ def flush
# this is a Windows security feature with the v1 COM APIs that prevent
# arbitrary reassignment of a task scheduler command to run as SYSTEM
# without the authorization to do so
self.user = resource[:user]
self.user = resource[:user] unless resource[:group]
task.save
@task = nil
end
Expand Down
22 changes: 20 additions & 2 deletions lib/puppet/provider/scheduled_task/win32_taskscheduler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ def user
account
end

def group
task.group_information
end

def trigger
@triggers ||= task.triggers.compact # remove nils for unsupported trigger types
end
Expand All @@ -72,6 +76,14 @@ def user_insync?(current, should)
Puppet::Util::Windows::SID.name_to_sid(current) == Puppet::Util::Windows::SID.name_to_sid(should[0])
end

def group_insync?(current, should)
return false unless current

# By comparing account SIDs we don't have to worry about case
# sensitivity, or canonicalization of the account name.
Puppet::Util::Windows::SID.name_to_sid(current) == Puppet::Util::Windows::SID.name_to_sid(should[0])
end

def trigger_insync?(current, should)
should = [should] unless should.is_a?(Array)
current = [current] unless current.is_a?(Array)
Expand Down Expand Up @@ -153,12 +165,18 @@ def user=(value)
end
end

def group=(value)
raise("Invalid group: #{value}") unless Puppet::Util::Windows::SID.name_to_sid(value)

task.set_group_information(value)
end

def create
@triggers = nil
@task = PuppetX::PuppetLabs::ScheduledTask::Task.new(resource[:name], :v1_compatibility)
self.command = resource[:command]

[:arguments, :working_dir, :enabled, :trigger, :user, :description].each do |prop|
[:arguments, :working_dir, :enabled, :trigger, :user, :group, :description].each do |prop|
send("#{prop}=", resource[prop]) if resource[prop]
end
end
Expand All @@ -177,7 +195,7 @@ def flush
# this is a Windows security feature with the v1 COM APIs that prevent
# arbitrary reassignment of a task scheduler command to run as SYSTEM
# without the authorization to do so
self.user = resource[:user]
self.user = resource[:user] unless resource[:group]
task.save
@task = nil
end
Expand Down
17 changes: 15 additions & 2 deletions lib/puppet/type/scheduled_task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@
completed successfully'. It is recommended that you either
choose another user to run the scheduled task, or alter the
security policy to allow v1 scheduled tasks to run as the
'SYSTEM' account. Defaults to 'SYSTEM'.
'SYSTEM' account.
Defaults to 'SYSTEM' unless the group property is set.

Please also note that Puppet must be running as a privileged user
in order to manage `scheduled_task` resources. Running as an
Expand All @@ -88,7 +89,7 @@
Managed Service Account (gMSA), the task will be created with
`Run only when user is logged on` specified."

defaultto :system
defaultto { :system if @resource[:group].nil? || @resource[:group].empty? }

def insync?(current)
provider.user_insync?(current, @should)
Expand All @@ -103,6 +104,18 @@ def insync?(current)
to determine if a scheduled task is in sync or not."
end

newproperty(:group) do
desc "The group to run the scheduled task as.

Please also note that Puppet must be running as a privileged user
in order to manage `scheduled_task` resources. Running as an
unprivileged user will result in 'access denied' errors."

def insync?(current)
provider.group_insync?(current, @should)
end
end

newproperty(:compatibility, required_features: :compatibility) do
desc "The compatibility level associated with the task. May currently be set
to 1 for compatibility with tasks on a Windows XP or Windows Server
Expand Down
29 changes: 28 additions & 1 deletion lib/puppet_x/puppet_labs/scheduled_task/task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -218,10 +218,15 @@ def initialize(task_name, compatibility_level = nil)
# definition populated when task exists, otherwise new
@task, @definition = self.class.task(@full_task_path)
task_userid = @definition.Principal.UserId || ''
task_groupid = @definition.Principal.GroupId || ''

self.compatibility = TASK_COMPATIBILITY::TASK_COMPATIBILITY_V1 if compatibility_level == :v1_compatibility

set_account_information(task_userid, nil)
if task_groupid == ''
set_group_information(task_groupid)
else
set_account_information(task_userid, nil)
end
end

# API v1 Compatibility list
Expand Down Expand Up @@ -320,6 +325,8 @@ def save
task_user = nil
task_password = nil

# user and password should be nil if task should run in
# service account or group context
case @definition.Principal.LogonType
when TASK_LOGON_TYPE::TASK_LOGON_PASSWORD,
TASK_LOGON_TYPE::TASK_LOGON_INTERACTIVE_TOKEN_OR_PASSWORD
Expand Down Expand Up @@ -369,6 +376,18 @@ def set_account_information(user, password)
true
end

# Sets the +group+ for the given task if the task should run in a group context.
# If successfull then true is returned.
#
def set_group_information(group)
@definition.Principal.RunLevel = TASK_RUNLEVEL_TYPE::TASK_RUNLEVEL_HIGHEST

@definition.Principal.GroupId = group
@definition.Principal.LogonType = TASK_LOGON_TYPE::TASK_LOGON_GROUP

true
end

# Returns the user associated with the task or nil if no user has yet
# been associated with the task.
#
Expand All @@ -377,6 +396,14 @@ def account_information
principal&.UserId
end

# Returns the group associated with the task or nil if no group has yet
# been associated with the task.
#
def group_information
principal = @definition.Principal
principal&.GroupId
end

# Returns the name of the application associated with the task.
#
def application_name
Expand Down