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.
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'
$severityFilter.Values.Add('Critical')
$classificationFilter = New-Object Amazon.SimpleSystemsManagement.Model.PatchFilter
$classificationFilter.Key = 'CLASSIFICATION'
$classificationFilter.Values.Add( 'CriticalUpdates' )
$ruleFilters.PatchFilters.Add($severityFilter)
$ruleFilters.PatchFilters.Add($classificationFilter)
$rule.PatchFilterGroup = $ruleFilters
New-SSMPatchBaseline -Name 'Critical-Updates' -Description 'Baseline containing all critical update' -ApprovalRules_PatchRule $rule
pb-07fadfc632e491110
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 : 10.0.0.9
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
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.
{
"Version":"2012-10-17",
"Statement":[
{
"Effect":"Allow",
"Principal":{
"Service":[
"ssm.amazonaws.com",
"ec2.amazonaws.com",
"sns.amazonaws.com"
]
},
"Action":"sts:AssumeRole"
}
]
}
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 *)'
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
70c354c1-3d71-4626-9742-8d962a9ce568
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
4999e319-b6cd-49f3-a526-23fe08c1f1cd
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.
Adam Bertram is a 25+ year IT veteran and an experienced online business professional. He’s a successful blogger, consultant, 6x Microsoft MVP, trainer, published author and freelance writer for dozens of publications. For how-to tech tutorials, catch up with Adam at adamtheautomator.com, connect on LinkedIn or follow him on X at @adbertram.
Let our experts teach you how to use Sitefinity's best-in-class features to deliver compelling digital experiences.
Learn MoreSubscribe to get all the news, info and tutorials you need to build better business apps and sites