How to Use AWS Systems Manager to Keep Your Windows Servers Patched

How to Use AWS Systems Manager to Keep Your Windows Servers Patched

Windows patching is an unfortunate requirement for all Windows administrators. Patch Tuesdays keep coming with no end in sight.

Many people use Windows Server Update Services (WSUS) to keep their Windows servers patched; it's free and works for the most part. The problem is it's yet another server you have to manage. It also usually depends on Active Directory and relies on Group Policy Objects (GPO) to configure the servers to point to WSUS. Using AWS's Systems Manager alleviates these and many other issues admins have with WSUS.

AWS Systems Manager or SSM is a free service provided by AWS which allows you to manage AWS EC2 instances as well as on-premises nodes through a lightweight agent. For patching, it brings together both EC2 and on-premises nodes so you can keep everything patched in one console.

Related: Managing Amazon S3 With Python

In this article, let's go over how to get it setup and running on your first Windows server. To do that, you'll first need to ensure you have the agent already setup. You can refer to the AWS documentation for instructions on how to make that happen. Once you've got an SSM agent setup on your Windows servers you're then ready to setup patching.

Creating a Patch Baseline

We'll first create a patch baseline. The patch baseline allows you to set which kinds of patches get installed on your servers. Patch baselines allow you to set different criteria depending on the category, severity and so on of the various patches.


In this article, I'll be creating a baseline that will only be for Windows servers that will have critical updates with an auto-approval of seven days. Let's make this happen in PowerShell.

Unfortunately, the PowerShell code to do this isn't exactly pretty but this is what I'm here for. Simply copy this out and run it! The code below creates our baseline with the name of Critical-Updates.

$autoApproveInDays = 7

$rule = New-Object Amazon.SimpleSystemsManagement.Model.PatchRule
$rule.ApproveAfterDays = $autoApproveInDays

$ruleFilters = New-Object Amazon.SimpleSystemsManagement.Model.PatchFilterGroup
$patchFilter = New-Object Amazon.SimpleSystemsManagement.Model.PatchFilter

$severityFilter = New-Object Amazon.SimpleSystemsManagement.Model.PatchFilter
$severityFilter.Key = 'MSRC_SEVERITY'

$classificationFilter = New-Object Amazon.SimpleSystemsManagement.Model.PatchFilter
$classificationFilter.Key = 'CLASSIFICATION'
$classificationFilter.Values.Add( 'CriticalUpdates' )

$rule.PatchFilterGroup = $ruleFilters

New-SSMPatchBaseline -Name 'Critical-Updates' -Description 'Baseline containing all critical update' -ApprovalRules_PatchRule $rule


Adding Managed Instances to Patch Groups

Next, we can add the instances to patch groups. Creating patch groups allows you to deliver different patches to different instances more easily. To use patch groups, we need to tag our instances. For this example, perhaps I have a server that's in production so I'll assign it to a patch group called Production.

I first need to get the managed instance ID, and I can then use that to assign the tag.

PS C:\Users\adam> Get-SSMInstanceInformation

ActivationId                           : 1c6f3fac-0cdd-4d9e-a32e-c7cae4231495
AgentVersion                           : 2.2.493.0
AssociationOverview                    :
AssociationStatus                      :
ComputerName                           : SRV1.WORKGROUP
IamRole                                : SSMServiceRole
InstanceId                             : mi-07fae420a558c8281
IPAddress                              :
IsLatestVersion                        : True
LastAssociationExecutionDate           : 1/1/0001 12:00:00 AM
LastPingDateTime                       : 4/27/2018 5:01:07 PM
LastSuccessfulAssociationExecutionDate : 1/1/0001 12:00:00 AM
Name                                   : SRV1
PingStatus                             : Online
PlatformName                           : Microsoft Windows Server 2016 Datacenter
PlatformType                           : Windows
PlatformVersion                        : 10.0.14393
RegistrationDate                       : 4/27/2018 4:53:27 PM
ResourceType                           : ManagedInstance

PS> $tag = New-Object Amazon.SimpleSystemsManagement.Model.Tag
>> $tag.Key = 'Patch Group'
>> $tag.Value = 'Production'
>> Add-SSMResourceTag -ResourceType 'ManagedInstance' -ResourceId 'mi-07fae420a558c8281' -Tag $tag

Creating a Maintenance Window

A maintenance window is required to install patches via SSM. To do that, we'll need an IAM role to control access to the maintenance window. I'll create one with PowerShell using the below JSON file which I'll call C:.json.


Next, I'll create the role. I can do this a number of different ways but I'm most comfortable with PowerShell so I'll use that.

PS C:\Users\adam> New-IAMRole -RoleName 'mw-task-role' -AssumeRolePolicyDocument (Get-Content -Raw C:\MaintenanceWindowRole.json)

Path             RoleName                           RoleId                   CreateDate             Description
----             --------                           ------                   ----------             -----------
/                mw-task-role                       AROAIBV5ZRXZCOXC535PQ    4/27/2018 4:27:14 PM

Next, we need to create a maintenance window. I'll use the New-SSMMaintenanceWindow command to do that. Below I'm creating a maintenance window that triggers every Tuesday at 4PM for four hours that cuts off any new tasks one hour before the maintenance window expires.

PS> New-SSMMaintenanceWindow -Name 'EveryTuesday' -Duration 4 -Cutoff 1 -Schedule 'cron(0 16 ? * TUE *)'

Registering the Patch Group with the Maintenance Window

Once we've got the maintenance window created, we need to associate the patch group with the maintenance window.

## Find the maintenance window ID
PS> Get-SSMMaintenanceWindowList

Cutoff      : 1
Description :
Duration    : 4
Enabled     : True
Name        : EveryTuesday
WindowId    : mw-01d06df5638742bb4

## Build the target query
PS> $target = @{Key="tag:Patch Group";Values=@("Production")}

## Register the target
PS> Register-SSMTargetWithMaintenanceWindow -WindowId 'mw-01d06df5638742bb4' -Target $target -ResourceType INSTANCE

Registering the Install Task with the Maintenance Window

Once we've got the patch group associated with the maintenance window, we can setup a task to scan for and install the necessary updates.

PS> $maintenanceWindowId = (Get-SSMMaintenanceWindowList | Where-Object {$_.Name -eq 'EveryTuesday'}).WindowId
PS> $windowTargetId = (Get-SSMMaintenanceWindowTarget -WindowId $maintenanceWindowId).WindowTargetId
PS> $windowRoleArn = (Get-IAMRole -RoleName mw-task-role).Arn

PS> $parameters = @{}
PS> $parameterValues = New-Object Amazon.SimpleSystemsManagement.Model.MaintenanceWindowTaskParameterValueExpression
PS> $parameterValues.Values = @("Install")
PS> $parameters.Add("Operation", $parameterValues)

PS> Register-SSMTaskWithMaintenanceWindow -WindowId $maintenanceWindowId -TaskArn 'AWS-ApplyPatchBaseline' -Target @{ Key="WindowTargetIds";Values=$windowTargetId } -TaskType "RUN_COMMAND" -TaskParameter $parameters -ServiceRoleArn $windowRoleArn -MaxConcurrency 1 -MaxError 1



Once you've got the install task registered, you're done! SSM can seem daunting at first especially if you don't have a lot of AWS experience but hopefully with this tutorial, you'll now be able to copy/paste some of this PowerShell code to give you a jump start.

Related Posts

Comments are disabled in preview mode.
Loading animation