Introduction
Every Windows administrator has been there: you've just finished hardening 50 servers according to CIS benchmarks, only to discover that server #23 somehow reverted three critical settings overnight. Configuration drift isn't just frustrating—it's a compliance nightmare waiting to happen.
What if I told you there's a way to make configuration drift impossible?
The answer lies in automation, but not just any automation—we need to automate the right standards. Enter CIS benchmarks: the industry-recognized gold standard for system hardening. These benchmarks provide hundreds of specific recommendations to reduce your attack surface and meet compliance requirements for frameworks like PCI-DSS, HIPAA, and SOC 2. But implementing them manually? That's still a recipe for burnout and the exact drift problem we're trying to solve.
The real solution lies in combining PowerShell Desired State Configuration (DSC) with AWS Systems Manager. This powerful duo transforms Windows security from a manual checklist into Infrastructure as Code. You'll get centralized management through AWS, continuous compliance enforcement, and the peace of mind that comes from knowing your servers are always configured correctly—and stay that way.
Understanding the Components
PowerShell DSC Primer
PowerShell Desired State Configuration represents a fundamental shift in how we think about system configuration. Instead of writing scripts that tell a system how to reach a desired state, DSC lets you declare what that state should be. The system figures out the rest.
Think of it this way: traditional scripts are like giving turn-by-turn directions to a destination. DSC is like giving someone the address and letting their GPS figure out the route. If they take a wrong turn (configuration drift), the GPS (DSC engine) automatically recalculates and gets them back on track.
Key DSC concepts include:
- Resources: The building blocks that define individual settings (registry keys, services, features)
- Configurations: PowerShell scripts that group resources together
- MOF files: The compiled output that DSC engines actually process
CIS Benchmarks and the CisDsc Module
The Center for Internet Security (CIS) benchmarks are consensus-based security configuration guides used by organizations worldwide. They're divided into two levels:
- Level 1: Basic security settings that should work for most organizations
- Level 2: Defense-in-depth settings for high-security environments
The CisDsc module is where the magic happens. It translates over 300 CIS benchmark recommendations into DSC resources. Instead of manually configuring settings like:
- Disabling unnecessary services (Telnet, TFTP)
- Enforcing password policies (complexity, history, age)
- Configuring audit policies for security events
- Hardening network protocols and permissions
You simply declare that you want CIS Level 1 compliance, and DSC handles the rest.
AWS Systems Manager's Role
AWS Systems Manager serves as our delivery mechanism, and it's perfect for this use case. Unlike traditional DSC pull servers that require additional infrastructure, Systems Manager leverages AWS's existing management plane.
State Manager associations ensure your configurations are continuously enforced, while Run Command provides on-demand execution. The benefits over traditional approaches are significant:
- No additional infrastructure to maintain
- Built-in high availability
- Native AWS IAM integration
- Seamless integration with CloudWatch, S3, and other AWS services
Architecture Overview
High-Level Architecture
Our solution architecture leverages several AWS services working in concert:
┌─────────────────────┐
│ S3 Bucket │
│ (DSC Configurations)│
└──────────┬──────────┘
│
┌────▼────┐
│ AWS │
│ Systems │
│ Manager │
└────┬────┘
│
┌──────▼──────┐
│ SSM Agent │
│ (on each │
│ instance) │
└──────┬──────┘
│
┌──────▼──────┐
│ PowerShell │
│ DSC │
│ Engine │
└─────────────┘
Component Interactions
The workflow is elegantly simple:
- DSC configurations are stored as MOF files in S3
- Systems Manager State Manager associations define which configurations apply to which instances
- SSM Agent on each instance retrieves and applies configurations
- Compliance data flows back to Systems Manager Inventory
- CloudWatch captures all logs and metrics for monitoring and alerting
Security Considerations
Security is built into every layer:
- No inbound ports required: SSM Agent makes outbound HTTPS connections only
- IAM-based authentication: No passwords or keys to manage
- Encrypted communication: All data in transit uses TLS
- Complete audit trail: Every action is logged in CloudTrail
Prerequisites and Initial Setup
AWS Prerequisites
Before we begin, ensure you have:
- An RDP client, we will be using Windows RDP to interact with the VMs.
- An AWS account with appropriate administrative permissions
- A VPC with the ability to launch Windows Server EC2 instances (2016, 2019, or 2022 recommended)
- Basic Systems Manager prerequisites:
- SSM Agent (pre-installed on Windows AMIs dated 2016.11 or later)
- IAM instance profile with the AmazonSSMManagedInstanceCore policy
- Outbound HTTPS connectivity to Systems Manager endpoints
Setting Up IAM Role
First, create a role that allows EC2 instances to be managed by Systems Manager. Navigate to IAM -> Roles.

Select Create Role in the top right. Then pick AWS service and in the use case drop down select EC2 and Next.

Use the search box and attach the following AWS managed policies to this role:
AmazonSSMManagedInstanceCore
: Basic Systems Manager functionalityAmazonS3FullAccess
: We're going to upload a file to S3 from an EC2CloudWatchAgentServerPolicy
: For logging (optional but recommended)
After selecting the policies, hit Next.
Let's name the role something descriptive like EC2-SSM-Role
and a brief description like Allows EC2 instances to use Systems Manager
. Take note of the json here for future reference if you'd rather use cli or another IaC tool.
Finally, Create role.

Assigning the Role as a launch template
AWS creates an instance profile for the role automatically, now we need to associate it with your Windows instances. This enables secure communication without storing credentials on the instances.
You could manually attach the role to each Windows Server as you're creating them, but why be tedious when you can automate? We will make a launch template.
Navigate to EC2 -> Launch Templates

Fill out the fields. I'm going to make my Launch template name WS-SSM-Template
and the Template version description Windows Server with SSM role
Scroll down a bit and go to the Quick Start section and let's pick the Server 2022 Base as that's most commonly used nowadays.

Instance Type we'll go with Micro to be free tier eligible, but for production we'd want at least Medium depending on how much we are configuring with DSC and it can be CPU intensive.

If you have a key pair already feel free to select it otherwise let's create one.

Network settings for subnet we are going to put Don't include in launch template so that we can pick each time. I'm going to then pick Select existing security group and choose default.
Ensure whatever Security Group you are selecting allows Outbound HTTPS (443) and Inbound TCP/3389 for RDP.

Let's establish some good practices now and add a couple Resource tags to this template:
Environment: Test
DSC-Config: CIS-Level1-WS22
Managed-By: SystemsManager

Then expand the Advanced details section and under IAM instance profile we select the role we made in the previous step.

We can pass over the other configurations for this demo and select Create launch template.

Now let's spin up a server. From the launch templates menu we can just Actions -> Launch instance from template

You see everything we picked is already populated, for Network Settings go ahead and pick a subnet (or create if you don't have any) and Launch Instance.
With that up and running successfully we'll go ahead now and look at some other prerequisites we need to knock out now.
Creating the S3 Bucket
Your DSC configurations need a home in S3. Create a dedicated bucket with versioning enabled. Note that naming must be globally unique, so get creative.
Via CLI:
# Create S3 bucket for DSC resources
aws s3 mb s3://systems-manager-windows-server-dsc-configurations
# Enable versioning for configuration history
aws s3api put-bucket-versioning `
--bucket systems-manager-windows-server-dsc-configurations `
--versioning-configuration Status=Enabled
# Add tags to the bucket
aws s3api put-bucket-tagging `
--bucket my-company-dsc-configurations `
--tagging 'TagSet=[
{
"Key":"Environment",
"Value":"Test"
},
{
"Key":"Purpose",
"Value":"DSC-Configurations"
},
{
"Key":"Project",
"Value":"Systems-Manager-Learning"
}
]'
Via GUI:
Search/navigate to S3 and then Create Bucket

The defaults for most things are alright, we want to change Bucket Versioning to Enable.

Throw in a couple tags for best practices:
Environment: Test
Purpose: DSC-Configurations
Project: Systems-Manager-Learning

Finally Create Bucket.
Installing and Configuring CisDsc
Installation Steps
Connect to your instance that you launched from the template, downloading the RDP file and using the keypair file you downloaded to decrypt the password.
Install the CisDsc and AWS S3 modules for Powershell:
# Install from PowerShell Gallery
Install-Module -Name CisDsc, AWS.Tools.S3 -Force -Scope AllUsers
# Verify installation
Get-Module -ListAvailable CisDsc
Get-Module -ListAvailable AWS.Tools.S3
Understanding Available Resources
Explore what's available in the module:
# See what type of CIS policies are available
Get-DscResource -Module CisDsc |
Select-Object Name, Properties |
Format-Table -AutoSize
# See what you can pass in and what is required
Get-DscResource -Name "CIS_Microsoft_Windows_Server_2022_Member_Server_Release_21H2" -Syntax
# Take a look at configuration examples they have already setup
$ResourcePath = "C:\Program Files\WindowsPowerShell\Modules\CisDsc\4.0.1"
Get-ChildItem $ResourcePath -Recurse -Filter "*.ps1" | Select-Object Name, FullName
# See what WS2022 specific example does
Get-Content "C:\Program Files\WindowsPowerShell\Modules\CisDsc\4.0.1\examples\CIS_Microsoft_Windows_Server_2022_Member_Server_Release_21H2_With_LAPS.ps1"
# Dive Deeper and see all the controls being applied
Get-Content "C:\Program Files\WindowsPowerShell\Modules\CisDsc\4.0.1\DSCResources\CIS_Microsoft_Windows_Server_2022_Member_Server_Release_21H2\CIS_Microsoft_Windows_Server_2022_Member_Server_Release_21H2.schema.psm1"
# Find only Password controls
$CompositeContent = Get-Content "C:\Program Files\WindowsPowerShell\Modules\CisDsc\4.0.1\DSCResources\CIS_Microsoft_Windows_Server_2022_Member_Server_Release_21H2\CIS_Microsoft_Windows_Server_2022_Member_Server_Release_21H2.schema.psm1"
$CompositeContent | Select-String -Pattern "Password|password" -Context 2
We can see that each setting has the actual control # and the CIS Level so that we can apply all Level 1 controls and then decide to exclude certain controls.
Your First Configuration Script
While the example scripts are great, let's make our own and create a basic CIS Level 1 configuration:
Configuration CISLevel1Baseline {
Import-DscResource -ModuleName CisDsc
Node localhost {
CIS_Microsoft_Windows_Server_2022_Member_Server_Release_21H2 BaselineLevel1 {
# Required String parameters - provide minimal values
Cis2316AccountsRenameGuestaccount = "GuestisRenamed"
Cis2374LegalNoticeText = "This is a Legal Text"
Cis2375LegalNoticeCaption = "This is a Legal Caption"
Cis2376CachedLogonsCount = "4"
Cis1849ScreensaverGracePeriod = "5"
# Optional: Exclude specific controls
ExcludeList = @(
'2.3.1.5', # Accounts: Administrator account status
'18.9.4.1' # MSS: (AutoAdminLogon)
)
}
}
}
# Generate MOF file
CISLevel1Baseline -OutputPath .\
The ExcludeList parameter is crucial – it lets you skip controls that might conflict with your environment. In this example, we're excluding the Administrator account status (you might need it enabled) and AutoAdminLogon (might be required for certain automation scenarios). Ignore that InfoSec scream you hear in the distance.
Looking at the localhost.mof
we just created we can see exactly what controls are being applied and what value they are given making it an excellent resource against configuration drift.
Now send that thing to the cloud and we'll use it in the next post.
# Upload to S3
Write-S3Object -BucketName "systems-manager-windows-server-dsc-configurations" -File ".\localhost.mof" -Key "localhost.mof"
# Verify it uploaded
Get-S3Object -BucketName "systems-manager-windows-server-dsc-configurations"
If you're using a personal tenant, spin everything down now.
Cost Considerations Overview
What's Free
The good news is that much of this solution leverages AWS's free tier:
- Systems Manager basic features: Free for the first 1,000 instances
- SSM Agent: Included with Windows AMIs at no extra charge
- Basic inventory and compliance viewing: No additional cost
What Costs Money
Your actual costs will be minimal:
- S3 storage: Pennies per month for configuration files
- CloudWatch Logs: $0.50 per GB ingested (optional but recommended)
- EC2 instance hours: Your existing compute costs
- Systems Manager advanced features: Only if you exceed free tier limits
Cost Estimation Example
For a typical deployment of 50 Windows Servers:
- S3 Storage: ~$0.50/month (assuming 1MB of configurations)
- Systems Manager: $0 (well within free tier)
- CloudWatch Logs: ~$5-10/month (depending on verbosity)
- Total additional cost: Under $15/month for enterprise-grade configuration management
Scale Considerations
As you scale, keep in mind:
- Costs grow linearly with instance count
- Performance impact during initial configuration can be significant
- AWS rate limits may require throttling for large deployments
- Consider phased rollouts for production environments
Next Steps and Series Preview
What We've Covered
In this first part, we've laid the groundwork:
- Understanding how DSC and CIS benchmarks solve real security challenges
- Exploring the architecture that makes this solution robust and scalable
- Setting up the prerequisites for your AWS environment
- Preparing our first configuration
Coming in Part 2
Next post in this series, we'll get our hands dirty with:
- Troubleshooting Systems Manager Agents
- Configuring Cloudwatch Agent
Resources
Helpful Links
- CIS Benchmarks Official Site
- AWS Systems Manager Documentation
- PowerShell DSC Overview
- CisDsc Module on PowerShell Gallery
Prerequisites Checklist
Before moving to Part 2, ensure you have:
- ✅ AWS account with administrative access
- ✅ Windows Server 2016/2019/2022 test instance
- ✅ IAM roles properly configured
- ✅ S3 bucket created with versioning enabled
- ✅ CisDsc module installed on test instance
- ✅ Basic familiarity with PowerShell
Ready to Transform Your Windows Security?
Try this implementation on a test instance this week. I'm genuinely curious about your results—hit me up in the comments:
- What surprised you most about the setup process?
- Which CIS controls are you most excited to automate?
- What Windows security challenges are keeping you up at night?
Part 2 drops when I get it ironed out and we'll tackle the deployment and watch our first configuration work its magic. Trust me, seeing 300+ security settings apply automatically never gets old.