Configure AWS Systems Manager Maintenance Window Tasks

The aws:ssm/maintenanceWindowTask:MaintenanceWindowTask resource, part of the Pulumi AWS provider, defines tasks that execute during Systems Manager maintenance windows: automation documents, Lambda functions, shell commands, or Step Functions workflows. This guide focuses on four capabilities: automation document execution, Lambda invocation, Run Command with logging, and Step Functions orchestration.

Maintenance window tasks belong to maintenance windows and target EC2 instances or window target groups. They may invoke Lambda functions, write to S3, send SNS notifications, or trigger Step Functions. The examples are intentionally small. Combine them with your own maintenance windows, targets, and execution infrastructure.

Restart EC2 instances using automation documents

Maintenance windows often execute AWS-provided automation documents to perform common operations like restarting instances during scheduled periods.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.ssm.MaintenanceWindowTask("example", {
    maxConcurrency: "2",
    maxErrors: "1",
    priority: 1,
    taskArn: "AWS-RestartEC2Instance",
    taskType: "AUTOMATION",
    windowId: exampleAwsSsmMaintenanceWindow.id,
    targets: [{
        key: "InstanceIds",
        values: [exampleAwsInstance.id],
    }],
    taskInvocationParameters: {
        automationParameters: {
            documentVersion: "$LATEST",
            parameters: [{
                name: "InstanceId",
                values: [exampleAwsInstance.id],
            }],
        },
    },
});
import pulumi
import pulumi_aws as aws

example = aws.ssm.MaintenanceWindowTask("example",
    max_concurrency="2",
    max_errors="1",
    priority=1,
    task_arn="AWS-RestartEC2Instance",
    task_type="AUTOMATION",
    window_id=example_aws_ssm_maintenance_window["id"],
    targets=[{
        "key": "InstanceIds",
        "values": [example_aws_instance["id"]],
    }],
    task_invocation_parameters={
        "automation_parameters": {
            "document_version": "$LATEST",
            "parameters": [{
                "name": "InstanceId",
                "values": [example_aws_instance["id"]],
            }],
        },
    })
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ssm"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := ssm.NewMaintenanceWindowTask(ctx, "example", &ssm.MaintenanceWindowTaskArgs{
			MaxConcurrency: pulumi.String("2"),
			MaxErrors:      pulumi.String("1"),
			Priority:       pulumi.Int(1),
			TaskArn:        pulumi.String("AWS-RestartEC2Instance"),
			TaskType:       pulumi.String("AUTOMATION"),
			WindowId:       pulumi.Any(exampleAwsSsmMaintenanceWindow.Id),
			Targets: ssm.MaintenanceWindowTaskTargetArray{
				&ssm.MaintenanceWindowTaskTargetArgs{
					Key: pulumi.String("InstanceIds"),
					Values: pulumi.StringArray{
						exampleAwsInstance.Id,
					},
				},
			},
			TaskInvocationParameters: &ssm.MaintenanceWindowTaskTaskInvocationParametersArgs{
				AutomationParameters: &ssm.MaintenanceWindowTaskTaskInvocationParametersAutomationParametersArgs{
					DocumentVersion: pulumi.String("$LATEST"),
					Parameters: ssm.MaintenanceWindowTaskTaskInvocationParametersAutomationParametersParameterArray{
						&ssm.MaintenanceWindowTaskTaskInvocationParametersAutomationParametersParameterArgs{
							Name: pulumi.String("InstanceId"),
							Values: pulumi.StringArray{
								exampleAwsInstance.Id,
							},
						},
					},
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.Ssm.MaintenanceWindowTask("example", new()
    {
        MaxConcurrency = "2",
        MaxErrors = "1",
        Priority = 1,
        TaskArn = "AWS-RestartEC2Instance",
        TaskType = "AUTOMATION",
        WindowId = exampleAwsSsmMaintenanceWindow.Id,
        Targets = new[]
        {
            new Aws.Ssm.Inputs.MaintenanceWindowTaskTargetArgs
            {
                Key = "InstanceIds",
                Values = new[]
                {
                    exampleAwsInstance.Id,
                },
            },
        },
        TaskInvocationParameters = new Aws.Ssm.Inputs.MaintenanceWindowTaskTaskInvocationParametersArgs
        {
            AutomationParameters = new Aws.Ssm.Inputs.MaintenanceWindowTaskTaskInvocationParametersAutomationParametersArgs
            {
                DocumentVersion = "$LATEST",
                Parameters = new[]
                {
                    new Aws.Ssm.Inputs.MaintenanceWindowTaskTaskInvocationParametersAutomationParametersParameterArgs
                    {
                        Name = "InstanceId",
                        Values = new[]
                        {
                            exampleAwsInstance.Id,
                        },
                    },
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.ssm.MaintenanceWindowTask;
import com.pulumi.aws.ssm.MaintenanceWindowTaskArgs;
import com.pulumi.aws.ssm.inputs.MaintenanceWindowTaskTargetArgs;
import com.pulumi.aws.ssm.inputs.MaintenanceWindowTaskTaskInvocationParametersArgs;
import com.pulumi.aws.ssm.inputs.MaintenanceWindowTaskTaskInvocationParametersAutomationParametersArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new MaintenanceWindowTask("example", MaintenanceWindowTaskArgs.builder()
            .maxConcurrency("2")
            .maxErrors("1")
            .priority(1)
            .taskArn("AWS-RestartEC2Instance")
            .taskType("AUTOMATION")
            .windowId(exampleAwsSsmMaintenanceWindow.id())
            .targets(MaintenanceWindowTaskTargetArgs.builder()
                .key("InstanceIds")
                .values(exampleAwsInstance.id())
                .build())
            .taskInvocationParameters(MaintenanceWindowTaskTaskInvocationParametersArgs.builder()
                .automationParameters(MaintenanceWindowTaskTaskInvocationParametersAutomationParametersArgs.builder()
                    .documentVersion("$LATEST")
                    .parameters(MaintenanceWindowTaskTaskInvocationParametersAutomationParametersParameterArgs.builder()
                        .name("InstanceId")
                        .values(exampleAwsInstance.id())
                        .build())
                    .build())
                .build())
            .build());

    }
}
resources:
  example:
    type: aws:ssm:MaintenanceWindowTask
    properties:
      maxConcurrency: 2
      maxErrors: 1
      priority: 1
      taskArn: AWS-RestartEC2Instance
      taskType: AUTOMATION
      windowId: ${exampleAwsSsmMaintenanceWindow.id}
      targets:
        - key: InstanceIds
          values:
            - ${exampleAwsInstance.id}
      taskInvocationParameters:
        automationParameters:
          documentVersion: $LATEST
          parameters:
            - name: InstanceId
              values:
                - ${exampleAwsInstance.id}

The taskArn property references an AWS automation document (AWS-RestartEC2Instance). The taskType property must be AUTOMATION. The automationParameters block passes the instance ID to the document, and documentVersion ensures you use the latest version. The targets property specifies which instances to operate on.

Invoke Lambda functions during maintenance windows

Custom maintenance logic often lives in Lambda functions that need to run on a schedule against specific instances.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as std from "@pulumi/std";

const example = new aws.ssm.MaintenanceWindowTask("example", {
    maxConcurrency: "2",
    maxErrors: "1",
    priority: 1,
    taskArn: exampleAwsLambdaFunction.arn,
    taskType: "LAMBDA",
    windowId: exampleAwsSsmMaintenanceWindow.id,
    targets: [{
        key: "InstanceIds",
        values: [exampleAwsInstance.id],
    }],
    taskInvocationParameters: {
        lambdaParameters: {
            clientContext: std.base64encode({
                input: "{\"key1\":\"value1\"}",
            }).then(invoke => invoke.result),
            payload: "{\"key1\":\"value1\"}",
        },
    },
});
import pulumi
import pulumi_aws as aws
import pulumi_std as std

example = aws.ssm.MaintenanceWindowTask("example",
    max_concurrency="2",
    max_errors="1",
    priority=1,
    task_arn=example_aws_lambda_function["arn"],
    task_type="LAMBDA",
    window_id=example_aws_ssm_maintenance_window["id"],
    targets=[{
        "key": "InstanceIds",
        "values": [example_aws_instance["id"]],
    }],
    task_invocation_parameters={
        "lambda_parameters": {
            "client_context": std.base64encode(input="{\"key1\":\"value1\"}").result,
            "payload": "{\"key1\":\"value1\"}",
        },
    })
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ssm"
	"github.com/pulumi/pulumi-std/sdk/go/std"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		invokeBase64encode, err := std.Base64encode(ctx, &std.Base64encodeArgs{
			Input: "{\"key1\":\"value1\"}",
		}, nil)
		if err != nil {
			return err
		}
		_, err = ssm.NewMaintenanceWindowTask(ctx, "example", &ssm.MaintenanceWindowTaskArgs{
			MaxConcurrency: pulumi.String("2"),
			MaxErrors:      pulumi.String("1"),
			Priority:       pulumi.Int(1),
			TaskArn:        pulumi.Any(exampleAwsLambdaFunction.Arn),
			TaskType:       pulumi.String("LAMBDA"),
			WindowId:       pulumi.Any(exampleAwsSsmMaintenanceWindow.Id),
			Targets: ssm.MaintenanceWindowTaskTargetArray{
				&ssm.MaintenanceWindowTaskTargetArgs{
					Key: pulumi.String("InstanceIds"),
					Values: pulumi.StringArray{
						exampleAwsInstance.Id,
					},
				},
			},
			TaskInvocationParameters: &ssm.MaintenanceWindowTaskTaskInvocationParametersArgs{
				LambdaParameters: &ssm.MaintenanceWindowTaskTaskInvocationParametersLambdaParametersArgs{
					ClientContext: pulumi.String(invokeBase64encode.Result),
					Payload:       pulumi.String("{\"key1\":\"value1\"}"),
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
using Std = Pulumi.Std;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.Ssm.MaintenanceWindowTask("example", new()
    {
        MaxConcurrency = "2",
        MaxErrors = "1",
        Priority = 1,
        TaskArn = exampleAwsLambdaFunction.Arn,
        TaskType = "LAMBDA",
        WindowId = exampleAwsSsmMaintenanceWindow.Id,
        Targets = new[]
        {
            new Aws.Ssm.Inputs.MaintenanceWindowTaskTargetArgs
            {
                Key = "InstanceIds",
                Values = new[]
                {
                    exampleAwsInstance.Id,
                },
            },
        },
        TaskInvocationParameters = new Aws.Ssm.Inputs.MaintenanceWindowTaskTaskInvocationParametersArgs
        {
            LambdaParameters = new Aws.Ssm.Inputs.MaintenanceWindowTaskTaskInvocationParametersLambdaParametersArgs
            {
                ClientContext = Std.Base64encode.Invoke(new()
                {
                    Input = "{\"key1\":\"value1\"}",
                }).Apply(invoke => invoke.Result),
                Payload = "{\"key1\":\"value1\"}",
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.ssm.MaintenanceWindowTask;
import com.pulumi.aws.ssm.MaintenanceWindowTaskArgs;
import com.pulumi.aws.ssm.inputs.MaintenanceWindowTaskTargetArgs;
import com.pulumi.aws.ssm.inputs.MaintenanceWindowTaskTaskInvocationParametersArgs;
import com.pulumi.aws.ssm.inputs.MaintenanceWindowTaskTaskInvocationParametersLambdaParametersArgs;
import com.pulumi.std.StdFunctions;
import com.pulumi.std.inputs.Base64encodeArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new MaintenanceWindowTask("example", MaintenanceWindowTaskArgs.builder()
            .maxConcurrency("2")
            .maxErrors("1")
            .priority(1)
            .taskArn(exampleAwsLambdaFunction.arn())
            .taskType("LAMBDA")
            .windowId(exampleAwsSsmMaintenanceWindow.id())
            .targets(MaintenanceWindowTaskTargetArgs.builder()
                .key("InstanceIds")
                .values(exampleAwsInstance.id())
                .build())
            .taskInvocationParameters(MaintenanceWindowTaskTaskInvocationParametersArgs.builder()
                .lambdaParameters(MaintenanceWindowTaskTaskInvocationParametersLambdaParametersArgs.builder()
                    .clientContext(StdFunctions.base64encode(Base64encodeArgs.builder()
                        .input("{\"key1\":\"value1\"}")
                        .build()).result())
                    .payload("{\"key1\":\"value1\"}")
                    .build())
                .build())
            .build());

    }
}
resources:
  example:
    type: aws:ssm:MaintenanceWindowTask
    properties:
      maxConcurrency: 2
      maxErrors: 1
      priority: 1
      taskArn: ${exampleAwsLambdaFunction.arn}
      taskType: LAMBDA
      windowId: ${exampleAwsSsmMaintenanceWindow.id}
      targets:
        - key: InstanceIds
          values:
            - ${exampleAwsInstance.id}
      taskInvocationParameters:
        lambdaParameters:
          clientContext:
            fn::invoke:
              function: std:base64encode
              arguments:
                input: '{"key1":"value1"}'
              return: result
          payload: '{"key1":"value1"}'

The taskArn property points to your Lambda function ARN. The taskType property must be LAMBDA. The lambdaParameters block passes data to the function: clientContext provides base64-encoded metadata, and payload contains the JSON input. Both are optional but shown here for completeness.

Execute shell commands with output logging

Run Command tasks execute shell scripts across instances, with results captured to S3 and notifications sent via SNS.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.ssm.MaintenanceWindowTask("example", {
    maxConcurrency: "2",
    maxErrors: "1",
    priority: 1,
    taskArn: "AWS-RunShellScript",
    taskType: "RUN_COMMAND",
    windowId: exampleAwsSsmMaintenanceWindow.id,
    targets: [{
        key: "InstanceIds",
        values: [exampleAwsInstance.id],
    }],
    taskInvocationParameters: {
        runCommandParameters: {
            outputS3Bucket: exampleAwsS3Bucket.id,
            outputS3KeyPrefix: "output",
            serviceRoleArn: exampleAwsIamRole.arn,
            timeoutSeconds: 600,
            notificationConfig: {
                notificationArn: exampleAwsSnsTopic.arn,
                notificationEvents: ["All"],
                notificationType: "Command",
            },
            parameters: [{
                name: "commands",
                values: ["date"],
            }],
        },
    },
});
import pulumi
import pulumi_aws as aws

example = aws.ssm.MaintenanceWindowTask("example",
    max_concurrency="2",
    max_errors="1",
    priority=1,
    task_arn="AWS-RunShellScript",
    task_type="RUN_COMMAND",
    window_id=example_aws_ssm_maintenance_window["id"],
    targets=[{
        "key": "InstanceIds",
        "values": [example_aws_instance["id"]],
    }],
    task_invocation_parameters={
        "run_command_parameters": {
            "output_s3_bucket": example_aws_s3_bucket["id"],
            "output_s3_key_prefix": "output",
            "service_role_arn": example_aws_iam_role["arn"],
            "timeout_seconds": 600,
            "notification_config": {
                "notification_arn": example_aws_sns_topic["arn"],
                "notification_events": ["All"],
                "notification_type": "Command",
            },
            "parameters": [{
                "name": "commands",
                "values": ["date"],
            }],
        },
    })
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ssm"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := ssm.NewMaintenanceWindowTask(ctx, "example", &ssm.MaintenanceWindowTaskArgs{
			MaxConcurrency: pulumi.String("2"),
			MaxErrors:      pulumi.String("1"),
			Priority:       pulumi.Int(1),
			TaskArn:        pulumi.String("AWS-RunShellScript"),
			TaskType:       pulumi.String("RUN_COMMAND"),
			WindowId:       pulumi.Any(exampleAwsSsmMaintenanceWindow.Id),
			Targets: ssm.MaintenanceWindowTaskTargetArray{
				&ssm.MaintenanceWindowTaskTargetArgs{
					Key: pulumi.String("InstanceIds"),
					Values: pulumi.StringArray{
						exampleAwsInstance.Id,
					},
				},
			},
			TaskInvocationParameters: &ssm.MaintenanceWindowTaskTaskInvocationParametersArgs{
				RunCommandParameters: &ssm.MaintenanceWindowTaskTaskInvocationParametersRunCommandParametersArgs{
					OutputS3Bucket:    pulumi.Any(exampleAwsS3Bucket.Id),
					OutputS3KeyPrefix: pulumi.String("output"),
					ServiceRoleArn:    pulumi.Any(exampleAwsIamRole.Arn),
					TimeoutSeconds:    pulumi.Int(600),
					NotificationConfig: &ssm.MaintenanceWindowTaskTaskInvocationParametersRunCommandParametersNotificationConfigArgs{
						NotificationArn: pulumi.Any(exampleAwsSnsTopic.Arn),
						NotificationEvents: pulumi.StringArray{
							pulumi.String("All"),
						},
						NotificationType: pulumi.String("Command"),
					},
					Parameters: ssm.MaintenanceWindowTaskTaskInvocationParametersRunCommandParametersParameterArray{
						&ssm.MaintenanceWindowTaskTaskInvocationParametersRunCommandParametersParameterArgs{
							Name: pulumi.String("commands"),
							Values: pulumi.StringArray{
								pulumi.String("date"),
							},
						},
					},
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.Ssm.MaintenanceWindowTask("example", new()
    {
        MaxConcurrency = "2",
        MaxErrors = "1",
        Priority = 1,
        TaskArn = "AWS-RunShellScript",
        TaskType = "RUN_COMMAND",
        WindowId = exampleAwsSsmMaintenanceWindow.Id,
        Targets = new[]
        {
            new Aws.Ssm.Inputs.MaintenanceWindowTaskTargetArgs
            {
                Key = "InstanceIds",
                Values = new[]
                {
                    exampleAwsInstance.Id,
                },
            },
        },
        TaskInvocationParameters = new Aws.Ssm.Inputs.MaintenanceWindowTaskTaskInvocationParametersArgs
        {
            RunCommandParameters = new Aws.Ssm.Inputs.MaintenanceWindowTaskTaskInvocationParametersRunCommandParametersArgs
            {
                OutputS3Bucket = exampleAwsS3Bucket.Id,
                OutputS3KeyPrefix = "output",
                ServiceRoleArn = exampleAwsIamRole.Arn,
                TimeoutSeconds = 600,
                NotificationConfig = new Aws.Ssm.Inputs.MaintenanceWindowTaskTaskInvocationParametersRunCommandParametersNotificationConfigArgs
                {
                    NotificationArn = exampleAwsSnsTopic.Arn,
                    NotificationEvents = new[]
                    {
                        "All",
                    },
                    NotificationType = "Command",
                },
                Parameters = new[]
                {
                    new Aws.Ssm.Inputs.MaintenanceWindowTaskTaskInvocationParametersRunCommandParametersParameterArgs
                    {
                        Name = "commands",
                        Values = new[]
                        {
                            "date",
                        },
                    },
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.ssm.MaintenanceWindowTask;
import com.pulumi.aws.ssm.MaintenanceWindowTaskArgs;
import com.pulumi.aws.ssm.inputs.MaintenanceWindowTaskTargetArgs;
import com.pulumi.aws.ssm.inputs.MaintenanceWindowTaskTaskInvocationParametersArgs;
import com.pulumi.aws.ssm.inputs.MaintenanceWindowTaskTaskInvocationParametersRunCommandParametersArgs;
import com.pulumi.aws.ssm.inputs.MaintenanceWindowTaskTaskInvocationParametersRunCommandParametersNotificationConfigArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new MaintenanceWindowTask("example", MaintenanceWindowTaskArgs.builder()
            .maxConcurrency("2")
            .maxErrors("1")
            .priority(1)
            .taskArn("AWS-RunShellScript")
            .taskType("RUN_COMMAND")
            .windowId(exampleAwsSsmMaintenanceWindow.id())
            .targets(MaintenanceWindowTaskTargetArgs.builder()
                .key("InstanceIds")
                .values(exampleAwsInstance.id())
                .build())
            .taskInvocationParameters(MaintenanceWindowTaskTaskInvocationParametersArgs.builder()
                .runCommandParameters(MaintenanceWindowTaskTaskInvocationParametersRunCommandParametersArgs.builder()
                    .outputS3Bucket(exampleAwsS3Bucket.id())
                    .outputS3KeyPrefix("output")
                    .serviceRoleArn(exampleAwsIamRole.arn())
                    .timeoutSeconds(600)
                    .notificationConfig(MaintenanceWindowTaskTaskInvocationParametersRunCommandParametersNotificationConfigArgs.builder()
                        .notificationArn(exampleAwsSnsTopic.arn())
                        .notificationEvents("All")
                        .notificationType("Command")
                        .build())
                    .parameters(MaintenanceWindowTaskTaskInvocationParametersRunCommandParametersParameterArgs.builder()
                        .name("commands")
                        .values("date")
                        .build())
                    .build())
                .build())
            .build());

    }
}
resources:
  example:
    type: aws:ssm:MaintenanceWindowTask
    properties:
      maxConcurrency: 2
      maxErrors: 1
      priority: 1
      taskArn: AWS-RunShellScript
      taskType: RUN_COMMAND
      windowId: ${exampleAwsSsmMaintenanceWindow.id}
      targets:
        - key: InstanceIds
          values:
            - ${exampleAwsInstance.id}
      taskInvocationParameters:
        runCommandParameters:
          outputS3Bucket: ${exampleAwsS3Bucket.id}
          outputS3KeyPrefix: output
          serviceRoleArn: ${exampleAwsIamRole.arn}
          timeoutSeconds: 600
          notificationConfig:
            notificationArn: ${exampleAwsSnsTopic.arn}
            notificationEvents:
              - All
            notificationType: Command
          parameters:
            - name: commands
              values:
                - date

The taskType property must be RUN_COMMAND. The runCommandParameters block configures execution: outputS3Bucket and outputS3KeyPrefix capture command output, serviceRoleArn grants permissions, and notificationConfig sends events to SNS. The parameters array passes commands to execute (here, the date command).

Trigger Step Functions workflows from maintenance windows

Complex maintenance workflows that require orchestration across multiple services can be modeled as Step Functions and triggered during maintenance windows.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.ssm.MaintenanceWindowTask("example", {
    maxConcurrency: "2",
    maxErrors: "1",
    priority: 1,
    taskArn: exampleAwsSfnActivity.id,
    taskType: "STEP_FUNCTIONS",
    windowId: exampleAwsSsmMaintenanceWindow.id,
    targets: [{
        key: "InstanceIds",
        values: [exampleAwsInstance.id],
    }],
    taskInvocationParameters: {
        stepFunctionsParameters: {
            input: "{\"key1\":\"value1\"}",
            name: "example",
        },
    },
});
import pulumi
import pulumi_aws as aws

example = aws.ssm.MaintenanceWindowTask("example",
    max_concurrency="2",
    max_errors="1",
    priority=1,
    task_arn=example_aws_sfn_activity["id"],
    task_type="STEP_FUNCTIONS",
    window_id=example_aws_ssm_maintenance_window["id"],
    targets=[{
        "key": "InstanceIds",
        "values": [example_aws_instance["id"]],
    }],
    task_invocation_parameters={
        "step_functions_parameters": {
            "input": "{\"key1\":\"value1\"}",
            "name": "example",
        },
    })
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ssm"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := ssm.NewMaintenanceWindowTask(ctx, "example", &ssm.MaintenanceWindowTaskArgs{
			MaxConcurrency: pulumi.String("2"),
			MaxErrors:      pulumi.String("1"),
			Priority:       pulumi.Int(1),
			TaskArn:        pulumi.Any(exampleAwsSfnActivity.Id),
			TaskType:       pulumi.String("STEP_FUNCTIONS"),
			WindowId:       pulumi.Any(exampleAwsSsmMaintenanceWindow.Id),
			Targets: ssm.MaintenanceWindowTaskTargetArray{
				&ssm.MaintenanceWindowTaskTargetArgs{
					Key: pulumi.String("InstanceIds"),
					Values: pulumi.StringArray{
						exampleAwsInstance.Id,
					},
				},
			},
			TaskInvocationParameters: &ssm.MaintenanceWindowTaskTaskInvocationParametersArgs{
				StepFunctionsParameters: &ssm.MaintenanceWindowTaskTaskInvocationParametersStepFunctionsParametersArgs{
					Input: pulumi.String("{\"key1\":\"value1\"}"),
					Name:  pulumi.String("example"),
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.Ssm.MaintenanceWindowTask("example", new()
    {
        MaxConcurrency = "2",
        MaxErrors = "1",
        Priority = 1,
        TaskArn = exampleAwsSfnActivity.Id,
        TaskType = "STEP_FUNCTIONS",
        WindowId = exampleAwsSsmMaintenanceWindow.Id,
        Targets = new[]
        {
            new Aws.Ssm.Inputs.MaintenanceWindowTaskTargetArgs
            {
                Key = "InstanceIds",
                Values = new[]
                {
                    exampleAwsInstance.Id,
                },
            },
        },
        TaskInvocationParameters = new Aws.Ssm.Inputs.MaintenanceWindowTaskTaskInvocationParametersArgs
        {
            StepFunctionsParameters = new Aws.Ssm.Inputs.MaintenanceWindowTaskTaskInvocationParametersStepFunctionsParametersArgs
            {
                Input = "{\"key1\":\"value1\"}",
                Name = "example",
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.ssm.MaintenanceWindowTask;
import com.pulumi.aws.ssm.MaintenanceWindowTaskArgs;
import com.pulumi.aws.ssm.inputs.MaintenanceWindowTaskTargetArgs;
import com.pulumi.aws.ssm.inputs.MaintenanceWindowTaskTaskInvocationParametersArgs;
import com.pulumi.aws.ssm.inputs.MaintenanceWindowTaskTaskInvocationParametersStepFunctionsParametersArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new MaintenanceWindowTask("example", MaintenanceWindowTaskArgs.builder()
            .maxConcurrency("2")
            .maxErrors("1")
            .priority(1)
            .taskArn(exampleAwsSfnActivity.id())
            .taskType("STEP_FUNCTIONS")
            .windowId(exampleAwsSsmMaintenanceWindow.id())
            .targets(MaintenanceWindowTaskTargetArgs.builder()
                .key("InstanceIds")
                .values(exampleAwsInstance.id())
                .build())
            .taskInvocationParameters(MaintenanceWindowTaskTaskInvocationParametersArgs.builder()
                .stepFunctionsParameters(MaintenanceWindowTaskTaskInvocationParametersStepFunctionsParametersArgs.builder()
                    .input("{\"key1\":\"value1\"}")
                    .name("example")
                    .build())
                .build())
            .build());

    }
}
resources:
  example:
    type: aws:ssm:MaintenanceWindowTask
    properties:
      maxConcurrency: 2
      maxErrors: 1
      priority: 1
      taskArn: ${exampleAwsSfnActivity.id}
      taskType: STEP_FUNCTIONS
      windowId: ${exampleAwsSsmMaintenanceWindow.id}
      targets:
        - key: InstanceIds
          values:
            - ${exampleAwsInstance.id}
      taskInvocationParameters:
        stepFunctionsParameters:
          input: '{"key1":"value1"}'
          name: example

The taskType property must be STEP_FUNCTIONS. The stepFunctionsParameters block provides the workflow input as JSON and assigns a name to the execution. This allows you to orchestrate multi-step maintenance operations that span multiple AWS services.

Beyond these examples

These snippets focus on specific maintenance window task features: automation documents and Lambda invocation, Run Command with S3 logging and SNS notifications, and Step Functions workflow orchestration. They’re intentionally minimal rather than full maintenance automation solutions.

The examples reference pre-existing infrastructure such as maintenance windows, EC2 instances or window targets, and Lambda functions, S3 buckets, SNS topics, IAM roles, or Step Functions for relevant examples. They focus on configuring the task rather than provisioning the surrounding infrastructure.

To keep things focused, common task patterns are omitted, including:

  • Service role configuration (serviceRoleArn)
  • Cutoff behavior for long-running tasks (cutoffBehavior)
  • Task descriptions and metadata (description)
  • Priority ordering for multiple tasks (priority)

These omissions are intentional: the goal is to illustrate how each task type is wired, not provide drop-in maintenance modules. See the SSM Maintenance Window Task resource reference for all available configuration options.

Let's configure AWS Systems Manager Maintenance Window Tasks

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Immutability & Limitations
What properties can't I change after creating a maintenance window task?
Both taskType and windowId are immutable. Changing either forces resource replacement, so plan these values carefully during initial creation.
Task Types & Configuration
What task types are available for maintenance window tasks?
Four types are supported: AUTOMATION (AWS automation documents), LAMBDA (Lambda functions), RUN_COMMAND (SSM commands), and STEP_FUNCTIONS (Step Functions activities).
How do I configure parameters for different task types?
Use taskInvocationParameters with the appropriate sub-block: automationParameters for AUTOMATION tasks, lambdaParameters for LAMBDA, runCommandParameters for RUN_COMMAND, or stepFunctionsParameters for STEP_FUNCTIONS.
Execution Control & Scheduling
What's the difference between maxConcurrency and maxErrors?
maxConcurrency controls how many targets the task can run on in parallel, while maxErrors sets the maximum number of errors allowed before the task stops being scheduled.
How does task priority work in maintenance windows?
Lower numbers mean higher priority (e.g., priority 1 runs before priority 2). Tasks with the same priority run in parallel.
What happens to tasks when the maintenance window cutoff time is reached?
Use cutoffBehavior to control this: CONTINUE_TASK lets tasks finish, while CANCEL_TASK stops them at cutoff.
Targeting & IAM Roles
How do I target instances vs window target IDs?
For instances, use Key=InstanceIds,Values=instanceid1,instanceid2. For window targets, use Key=WindowTargetIds,Values=targetid1,targetid2.
What happens if I don't specify a service role?
Systems Manager uses your account’s service-linked role. If no service-linked role exists, it’s created automatically for you.

Using a different cloud?

Explore compute guides for other cloud providers: