Managing scheduled tasks

Scheduled tasks can be created, edited, deleted, and launched programmatically via the dedicated ADSI interfaces. You can apply the principles outlined in this article to write standalone scripts and programs or build custom integrations with third-party software. PowerShell scripts that manage scheduled tasks can also be executed from within Adaxes, for instance, from other scheduled tasks, business rules, and custom commands.

Creating a scheduled task

The following code sample creates a scheduled task that is executed on users.

PowerShell
[Reflection.Assembly]::LoadWithPartialName("Softerra.Adaxes.Adsi")

# Connect to the Adaxes service.
$ns = New-Object "Softerra.Adaxes.Adsi.AdmNamespace"
$service = $ns.GetServiceDirectly("localhost")

# Bind to the scheduled tasks container
$containerPath = $service.Backend.GetConfigurationContainerPath("ScheduledTasks")
$container = $service.OpenObject($containerPath, $null, $null, 0)

# Create a new scheduled task.
$task = $container.Create("adm-ScheduledTask", "CN=My Task")

$task.ObjectType = "user"
$task.Description = "My description"
$task.Disabled = $false
$task.ExecutionMoment = "ADM_BUSINESSRULEEXECMOMENT_BEFORE"
$task.OperationType = "none"

# TODO: Specify the schedule for the task.

# Save the scheduled task.
$task.SetInfo()
C#
using Softerra.Adaxes.Adsi;
using Softerra.Adaxes.Interop.Adsi;
using Softerra.Adaxes.Interop.Adsi.BusinessRules;
using Softerra.Adaxes.Interop.Adsi.PersistentObjects;
using Softerra.Adaxes.Interop.Adsi.ScheduledTasks;

class Program
{
    static void Main(string[] args)
    {
        // Connect to the Adaxes service.
        AdmNamespace ns = new AdmNamespace();
        IAdmService service = ns.GetServiceDirectly("localhost");

        // Bind to the 'Scheduled Tasks' container
        string containerPath = service.Backend.GetConfigurationContainerPath("ScheduledTasks");
        IADsContainer container = (IADsContainer)service.OpenObject(
            containerPath, null, null, 0);

        // Create a new scheduled task.
        IAdmScheduledTask task = (IAdmScheduledTask)container.Create(
            "adm-ScheduledTask", "CN=My Task");

        task.ObjectType = "user";
        task.Description = "My description";
        task.Disabled = false;
        task.ExecutionMoment = ADM_BUSINESSRULEEXECMOMENT_ENUM.ADM_BUSINESSRULEEXECMOMENT_BEFORE;
        task.OperationType = "none";

        // TODO: Specify the schedule for the task.

        // Save the scheduled task.
        task.SetInfo();
    }
}

Details

To create a scheduled task, you need to connect to your Adaxes service and bind to the container where you want to create the task – for example, the root container for scheduled tasks also known as the ScheduledTasks container.

If your script will be executed inside Adaxes, it becomes even simpler. You don't have to explicitly connect to your Adaxes service. Instead, you can use a predefined PowerShell variable $Context to get the ADS path of the ScheduledTasks container and bind to it.

# Bind to the scheduled tasks container.
$containerPath = $Context.GetWellKnownContainerPath("ScheduledTasks")
$container = $Context.BindToObject($containerPath)
 How to create a scheduled task in a different container

To create a scheduled task in a specific container, you need to build the ADS path of that container and bind to it just like you would bind to the ScheduledTasks container. The AdsPath class contains methods that simplify manipulating ADS paths.

The following code sample creates a scheduled task in the container named My Container. The task will be executed on Group objects.

PowerShell
[Reflection.Assembly]::LoadWithPartialName("Softerra.Adaxes.Adsi")

# Connect to the Adaxes service.
$ns = New-Object "Softerra.Adaxes.Adsi.AdmNamespace"
$service = $ns.GetServiceDirectly("localhost")

# Bind to the scheduled tasks container.
$containerPath = $service.Backend.GetConfigurationContainerPath("ScheduledTasks")

# Build the ADS path of the nested container 'My Container' and bind to it.
$scheduledTasksPathObj = New-Object "Softerra.Adaxes.Adsi.AdsPath" $containerPath
$myContainerAdsPath = $scheduledTasksPathObj.CreateChildPath("CN=My Container")
$myContainer = $service.OpenObject($myContainerAdsPath, $null, $null, 0)

# Create a new scheduled task.
$task = $myContainer.Create("adm-ScheduledTask", "CN=My Task")

$task.ObjectType = "group"
$task.Description = "My description"
$task.Disabled = $false
$task.ExecutionMoment = "ADM_BUSINESSRULEEXECMOMENT_BEFORE"
$task.OperationType = "none"

# TODO: Specify the schedule for the task.

# Save the scheduled task.
$task.SetInfo()
C#
using Softerra.Adaxes.Adsi;
using Softerra.Adaxes.Interop.Adsi;
using Softerra.Adaxes.Interop.Adsi.BusinessRules;
using Softerra.Adaxes.Interop.Adsi.PersistentObjects;
using Softerra.Adaxes.Interop.Adsi.ScheduledTasks;

class Program
{
    static void Main(string[] args)
    {
        // Connect to the Adaxes service.
        AdmNamespace ns = new AdmNamespace();
        IAdmService service = ns.GetServiceDirectly("localhost");

        // Bind to the scheduled tasks container.
        string containerPath = service.Backend.GetConfigurationContainerPath("ScheduledTasks");

        // Build the ADS path of the nested container 'My Container' and bind to it.
        AdsPath scheduledTasksPathObj = new AdsPath(containerPath);
        AdsPath myContainerAdsPath = scheduledTasksPathObj.CreateChildPath("CN=My Container");

        IADsContainer myContainer = (IADsContainer)service.OpenObject(
            myContainerAdsPath.ToString(), null, null, 0);

        // Create a new scheduled task.
        IAdmScheduledTask task = (IAdmScheduledTask)myContainer.Create(
            "adm-ScheduledTask", "CN=My Task");

        task.ObjectType = "group";
        task.Description = "My description";
        task.Disabled = false;
        task.ExecutionMoment = ADM_BUSINESSRULEEXECMOMENT_ENUM.ADM_BUSINESSRULEEXECMOMENT_BEFORE;
        task.OperationType = "none";

        // TODO: Specify the schedule for the task.

        // Save the scheduled task.
        task.SetInfo();
    }
}    

For details about how to create containers for scheduled tasks, see Creating scheduled task containers.

After binding to the container, call the Create method of the IADsContainer interface supported by all containers.

The method takes two parameters. The first one is the object type, "adm-ScheduledTask" in our case. The second one is a relative distinguished name of the new task.

Mandatory properties

The object returned by Create implements the IAdmScheduledTask interface inherited from the IAdmBusinessRule interface. Using these interfaces, you need to specify mandatory scheduled task properties before you will be able to save it.

  • OperationType – must always be set to none.

  • ExecutionMoment – must always be set to ADM_BUSINESSRULEEXECMOMENT_BEFORE.

  • ObjectType – determines the type of objects the scheduled task will apply to. The object type name must be specified exactly as it is defined in your directory schema e.g. user, organizationalUnit. Each time the task runs, its actions will be executed once for every object of the selected type within the activity scope of the task.

Optional properties

You can specify optional scheduled task properties before saving it.

  • Description – the task description.

  • Disabled – if set to true, the scheduled task will be created in a disabled state.

  • DeleteTaskAfterExecution – set to true to automatically delete the task after execution. This property will take effect only if the task is configured to run only once. For details on setting the task schedule, see Defining the schedule below.

  • OwnerServiceDnsHostName – the DNS host name of the Adaxes service instance that will handle the task execution. If this service instance is down when it is time to run the task, another available service in the configuration set will take ownership of the task.

    If this property is not set, the service instance will be selected automatically every time the task runs.

  • IsOwnerServicePermanent – if set to true, the scheduled task will never run on any service instance other than the one specified in OwnerServiceDnsHostName. The task will not run at all while the specified service instance is down.

Finally, you can save the scheduled task by calling SetInfo. However, it is recommended to define the task schedule before saving.

Defining the schedule

Use the GetRecurrencePattern method of the IAdmScheduledTask interface to access the task schedule. The object returned by GetRecurrencePattern implements the IAdmRecurrencePattern interface that you can use to change the schedule properties.

Schedule properties

  • RecurrenceType – the schedule recurrence type e.g. hourly, daily, monthly, etc. For a list of possible recurrence types, see ADM_RECURRENCEPATTERNTYPE_ENUM.

  • Interval – the interval between task executions, based on the recurrence type. For example, every 10 minutes/hours/days.

    This property will take effect only if the recurrence type is one of the following:

    • ADM_RECURRENCEPATTERNTYPE_MINUTELY
    • ADM_RECURRENCEPATTERNTYPE_HOURLY
    • ADM_RECURRENCEPATTERNTYPE_DAILY
  • DayOfWeekMask – a combination of the ADM_DAYSOFWEEK_ENUM values, expressed as a bitmask. Specifies the days of the week when to execute the task. For example:

    $recurrencePattern.DayOfWeekMask = "ADM_DAYSOFWEEK_WEDNESDAY, ADM_DAYSOFWEEK_SATURDAY".

    This property will take effect only if the recurrence type is ADM_RECURRENCEPATTERNTYPE_WEEKLY.

  • DayOfMonth – the day of the month when to execute the task. The value must be between 1 and 31, inclusive, or -1 to run the task on the last day of each month.

    This property will take effect only if the recurrence type is ADM_RECURRENCEPATTERNTYPE_MONTHLY.

  • PatternStartDateTime – the date and time when to execute the task for the first time. A value must be set if the recurrence type is ADM_RECURRENCEPATTERNTYPE_ONCE. Can be omitted with any other recurrence type or set to a specific date to precisely schedule the first execution.

  • NotBeforeDateTime – the date and time after which the task will be allowed to run. If set, the task will follow its recurrence pattern but will not be executed until this date. For example, if a task is configured to run on the 11th of each month and this property is set to November 12, 2023, the task will run for the first time on December 11, 2023.

When done configuring the schedule, apply it to the scheduled task using the SetRecurrencePattern method of the IAdmScheduledTask interface.

Examples

 Example 1 – Execute the task once (in 30 days after creation) and delete after execution
PowerShell
# The $task variable refers to a scheduled task.       
$recurrencePattern = $task.GetRecurrencePattern()

$recurrencePattern.RecurrenceType = "ADM_RECURRENCEPATTERNTYPE_ONCE"
$recurrencePattern.PatternStartDateTime = (Get-Date).AddDays(30)
$task.SetRecurrencePattern($recurrencePattern)

$task.DeleteTaskAfterExecution = $true
C#
// The task variable refers to a scheduled task.
IAdmRecurrencePattern recurrencePattern = task.GetRecurrencePattern();

recurrencePattern.RecurrenceType = ADM_RECURRENCEPATTERNTYPE_ENUM.ADM_RECURRENCEPATTERNTYPE_ONCE;
recurrencePattern.PatternStartDateTime = DateTime.Now.AddDays(30);
task.SetRecurrencePattern(recurrencePattern);

task.DeleteTaskAfterExecution = true;
 Example 2 – Execute the task every two hours
PowerShell
# The $task variable refers to a scheduled task.
$recurrencePattern = $task.GetRecurrencePattern()

$recurrencePattern.RecurrenceType = "ADM_RECURRENCEPATTERNTYPE_HOURLY"
$recurrencePattern.Interval = 2
$task.SetRecurrencePattern($recurrencePattern)
C#
// The task variable refers to a scheduled task.
IAdmRecurrencePattern recurrencePattern = task.GetRecurrencePattern();

recurrencePattern.RecurrenceType = ADM_RECURRENCEPATTERNTYPE_ENUM.ADM_RECURRENCEPATTERNTYPE_HOURLY;
recurrencePattern.Interval = 2;
task.SetRecurrencePattern(recurrencePattern);
 Example 3 – Execute the task every day at 4:00 AM
PowerShell
# The $task variable refers to a scheduled task.
$recurrencePattern = $task.GetRecurrencePattern()

$recurrencePattern.RecurrenceType = "ADM_RECURRENCEPATTERNTYPE_DAILY"
$recurrencePattern.Interval = 1

# Run at 4:00 AM.
$recurrencePattern.PatternStartDateTime = Get-Date -Hour 4 -Minute 0 -Second 0
$task.SetRecurrencePattern($recurrencePattern)
C#
// The task variable refers to a scheduled task.
IAdmRecurrencePattern recurrencePattern = task.GetRecurrencePattern();

recurrencePattern.RecurrenceType = ADM_RECURRENCEPATTERNTYPE_ENUM.ADM_RECURRENCEPATTERNTYPE_DAILY;
recurrencePattern.Interval = 1;

// Run at 4:00 AM.
DateTime now = DateTime.Now;
recurrencePattern.PatternStartDateTime = new(now.Year, now.Month, now.Day, 4, 0, 0);
task.SetRecurrencePattern(recurrencePattern);
 Example 4 – Execute the task every Wednesday and Saturday at 2:00 AM, starting on Saturday
PowerShell
# The $task variable refers to a scheduled task.
$recurrencePattern = $task.GetRecurrencePattern()

# Run weekly.
$recurrencePattern.RecurrenceType = "ADM_RECURRENCEPATTERNTYPE_WEEKLY"
$recurrencePattern.DayOfWeekMask = "ADM_DAYSOFWEEK_WEDNESDAY, ADM_DAYSOFWEEK_SATURDAY"

# At 2:00 AM.
$startDateTime = Get-Date -Hour 2 -Minute 0 -Second 0
$recurrencePattern.PatternStartDateTime = $startDateTime

# Start on Saturday.
while ($startDateTime.DayOfWeek -ne "Saturday") 
{ 
    $startDateTime = $startDateTime.AddDays(1) 
}
$recurrencePattern.NotBeforeDateTime = $startDateTime.AddMinutes(-1)

$task.SetRecurrencePattern($recurrencePattern)
C#
// The task variable refers to a scheduled task.
IAdmRecurrencePattern recurrencePattern = task.GetRecurrencePattern();

// Run weekly.
recurrencePattern.RecurrenceType = ADM_RECURRENCEPATTERNTYPE_ENUM.ADM_RECURRENCEPATTERNTYPE_WEEKLY;
recurrencePattern.DayOfWeekMask =
    ADM_DAYSOFWEEK_ENUM.ADM_DAYSOFWEEK_WEDNESDAY |
    ADM_DAYSOFWEEK_ENUM.ADM_DAYSOFWEEK_SATURDAY;

// At 2:00 AM.        
DateTime now = DateTime.Now;
DateTime startDateTime = new(now.Year, now.Month, now.Day, 2, 0, 0);
recurrencePattern.PatternStartDateTime = startDateTime;

// Start on Saturday.
while (startDateTime.DayOfWeek != DayOfWeek.Saturday)
{
    startDateTime = startDateTime.AddDays(1);
}
recurrencePattern.NotBeforeDateTime = startDateTime.AddMinutes(-1);
task.SetRecurrencePattern(recurrencePattern);
 Example 5 – Execute the task on the last day of each month at 1:00 PM
PowerShell
# The $task variable refers to a scheduled task.
$recurrencePattern = $task.GetRecurrencePattern()

$recurrencePattern.RecurrenceType = "ADM_RECURRENCEPATTERNTYPE_MONTHLY"
$recurrencePattern.DayOfMonth = -1
$recurrencePattern.PatternStartDateTime = Get-Date -Hour 13 -Minute 0 -Second 0
$task.SetRecurrencePattern($recurrencePattern)
C#
// The task variable refers to a scheduled task.
IAdmRecurrencePattern recurrencePattern = task.GetRecurrencePattern();

recurrencePattern.RecurrenceType = ADM_RECURRENCEPATTERNTYPE_ENUM.ADM_RECURRENCEPATTERNTYPE_MONTHLY;
recurrencePattern.DayOfMonth = -1;
DateTime now = DateTime.Now;
recurrencePattern.PatternStartDateTime = new(now.Year, now.Month, now.Day, 13, 0, 0);
task.SetRecurrencePattern(recurrencePattern);

Specifying actions and conditions

Use the ConditionedActions property of the IAdmBusinessRule interface to specify the actions and conditions of a scheduled task. This property is a collection that supports the IAdmCollection interface. Each item in the collection represents an action set – a block of conditions and actions that should be executed when the conditions are met.

For information on how to manage scheduled task actions and conditions, see Defining actions and conditions.

Setting activity scope

Use the ActivityScopeItems property of the IAdmBusinessRule interface to define the activity scope for a scheduled task. When a scheduled task runs, it is executed once for every object within the scope. Activity scope can include domains, members of groups, business units, objects located in specific organizational units, etc.

For information on how to define the activity scope of a scheduled task, see Defining the scope of activity.

Modifying a scheduled task

To modify an existing scheduled task, you need to connect to your Adaxes service and bind to the directory object representing the task.

If your script will be executed inside Adaxes, it is even simpler. You don't have to explicitly connect to your Adaxes service. Instead, you can get the ADS path of the ScheduledTasks container and bind to a task using a predefined PowerShell variable $Context.

$container = $Context.GetWellKnownContainerPath("ScheduledTasks")
$tasksPathObj = New-Object "Softerra.Adaxes.Adsi.AdsPath" $container
$taskPath = $tasksPathObj.CreateChildPath("CN=My Task")
$task = $Context.BindToObject($taskPath)

After binding to the task, you can use the IAdmBusinessRule, IAdmScheduledTask, and IADs interfaces to modify the task. To save the changes, call SetInfo.

Examples

The following code sample disables a scheduled task and changes the type of objects affected by the task.

PowerShell
[Reflection.Assembly]::LoadWithPartialName("Softerra.Adaxes.Adsi")

# Connect to the Adaxes service.
$ns = New-Object "Softerra.Adaxes.Adsi.AdmNamespace"
$service = $ns.GetServiceDirectly("localhost")

# Bind to the task.
$container = $service.Backend.GetConfigurationContainerPath("ScheduledTasks")
$tasksPathObj = New-Object "Softerra.Adaxes.Adsi.AdsPath" $container
$taskPath = $tasksPathObj.CreateChildPath("CN=My Task")
$task = $service.OpenObject($taskPath.ToString(), $null, $null, 0)

$task.ObjectType = "contact"
$task.Disabled = $true

# Save the changes.
$task.SetInfo()
C#
using Softerra.Adaxes.Adsi;
using Softerra.Adaxes.Interop.Adsi.PersistentObjects;
using Softerra.Adaxes.Interop.Adsi.ScheduledTasks;

class Program
{
    static void Main(string[] args)
    {
        // Connect to the Adaxes service.
        AdmNamespace ns = new AdmNamespace();
        IAdmService service = ns.GetServiceDirectly("localhost");

        / Bind to the task.
        string container = service.Backend.GetConfigurationContainerPath("ScheduledTasks");
        AdsPath tasksPathObj = new AdsPath(container);
        AdsPath taskPath = tasksPathObj.CreateChildPath("CN=My Task");
        IAdmScheduledTask task =
            (IAdmScheduledTask)service.OpenObject(taskPath.ToString(), null, null, 0);

        task.ObjectType = "contact";
        task.Disabled = true;

        // Save the changes.
        task.SetInfo();
    }
}

The following code sample clears the activity scope and deletes all actions and conditions from a scheduled task located in the container named My Container.

PowerShell
[Reflection.Assembly]::LoadWithPartialName("Softerra.Adaxes.Adsi")

# Connect to the Adaxes service.
$ns = New-Object "Softerra.Adaxes.Adsi.AdmNamespace"
$service = $ns.GetServiceDirectly("localhost")

# Bind to the task.
$container = $service.Backend.GetConfigurationContainerPath("ScheduledTasks")
$tasksPathObj = New-Object "Softerra.Adaxes.Adsi.AdsPath" $container
$myContainerPathObj = $tasksPathObj.CreateChildPath("CN=My Container")
$taskPath = $myContainerPathObj.CreateChildPath("CN=My Task")
$task = $service.OpenObject($taskPath.ToString(), $null, $null, 0)

$task.ConditionedActions.Clear()
$task.ActivityScopeItems.Clear()
C#
using Softerra.Adaxes.Adsi;
using Softerra.Adaxes.Interop.Adsi.PersistentObjects;
using Softerra.Adaxes.Interop.Adsi.ScheduledTasks;

class Program
{
    static void Main(string[] args)
    {
        // Connect to the Adaxes service.
        AdmNamespace ns = new AdmNamespace();
        IAdmService service = ns.GetServiceDirectly("localhost");

        // Bind to the task.
        string container = service.Backend.GetConfigurationContainerPath("ScheduledTasks");
        AdsPath tasksPathObj = new AdsPath(container);
        AdsPath myContainerPathObj = tasksPathObj.CreateChildPath("CN=My Container");
        AdsPath taskPath = myContainerPathObj.CreateChildPath("CN=My Task");
        IAdmScheduledTask task =
            (IAdmScheduledTask)service.OpenObject(taskPath.ToString(),
            null, null, 0);

        task.ConditionedActions.Clear();
        task.ActivityScopeItems.Clear();
    }
}

Executing a scheduled task

To execute a scheduled task, bind to it and call the RunNow method of the IAdmScheduledTask interface.

PowerShell
[Reflection.Assembly]::LoadWithPartialName("Softerra.Adaxes.Adsi")

# Connect to the Adaxes service.
$ns = New-Object "Softerra.Adaxes.Adsi.AdmNamespace"
$service = $ns.GetServiceDirectly("localhost")

$container = $service.Backend.GetConfigurationContainerPath("ScheduledTasks")
$tasksPathObj = New-Object "Softerra.Adaxes.Adsi.AdsPath" $container
$taskPath = $tasksPathObj.CreateChildPath("CN=My Task")
$task = $service.OpenObject($taskPath.ToString(), $null, $null, 0)

$task.RunNow()
C#
using Softerra.Adaxes.Adsi;
using Softerra.Adaxes.Interop.Adsi.PersistentObjects;
using Softerra.Adaxes.Interop.Adsi.ScheduledTasks;

class Program
{
    static void Main(string[] args)
    {
        // Connect to the Adaxes service.
        AdmNamespace ns = new AdmNamespace();
        IAdmService service = ns.GetServiceDirectly("localhost");

        // Bind to the task.
        string container = service.Backend.GetConfigurationContainerPath("ScheduledTasks");
        AdsPath tasksPathObj = new AdsPath(container);
        AdsPath taskPath = tasksPathObj.CreateChildPath("CN=My Task");
        IAdmScheduledTask task =
            (IAdmScheduledTask)service.OpenObject(taskPath.ToString(), null, null, 0);

        task.RunNow();
    }
}

See also